You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-07 23:02:56 +03:00
Improve test coverage and modernize style for interactive-auth (#2574)
* style: address no-mixed-operators errors,minor style improvements
* test: Fix async interactive-auth tests, add test case
* tests: Fix incorrectly stringified mock response
* pushprocessor: style update
* use async primitives in interactive-auth-spec
* lint
* fixup: remove duplicate test
* add test case for no-flow-with-session for interactive-auth
* interactive-auth: handle non-existing error.data
* async test fix
* test: add dummyauth test
* add testing for errcode
* Revert "pushprocessor: style update"
This reverts commit 3ed0fdfb73
.
* add testcase for missing error data
* test: move sessionId assignment
* Add tests to improve coverage for interactive-auth
* pushprocessor: style update
This commit is contained in:
@@ -32,8 +32,8 @@ class FakeClient {
|
||||
|
||||
const getFakeClient = (): MatrixClient => new FakeClient() as unknown as MatrixClient;
|
||||
|
||||
describe("InteractiveAuth", function() {
|
||||
it("should start an auth stage and complete it", function() {
|
||||
describe("InteractiveAuth", () => {
|
||||
it("should start an auth stage and complete it", async () => {
|
||||
const doRequest = jest.fn();
|
||||
const stateUpdated = jest.fn();
|
||||
|
||||
@@ -59,7 +59,7 @@ describe("InteractiveAuth", function() {
|
||||
});
|
||||
|
||||
// first we expect a call here
|
||||
stateUpdated.mockImplementation(function(stage) {
|
||||
stateUpdated.mockImplementation((stage) => {
|
||||
logger.log('aaaa');
|
||||
expect(stage).toEqual(AuthType.Password);
|
||||
ia.submitAuthDict({
|
||||
@@ -69,23 +69,130 @@ describe("InteractiveAuth", function() {
|
||||
|
||||
// .. which should trigger a call here
|
||||
const requestRes = { "a": "b" };
|
||||
doRequest.mockImplementation(function(authData) {
|
||||
doRequest.mockImplementation(async (authData) => {
|
||||
logger.log('cccc');
|
||||
expect(authData).toEqual({
|
||||
session: "sessionId",
|
||||
type: AuthType.Password,
|
||||
});
|
||||
return Promise.resolve(requestRes);
|
||||
return requestRes;
|
||||
});
|
||||
|
||||
return ia.attemptAuth().then(function(res) {
|
||||
expect(res).toBe(requestRes);
|
||||
expect(doRequest).toBeCalledTimes(1);
|
||||
expect(stateUpdated).toBeCalledTimes(1);
|
||||
});
|
||||
const res = await ia.attemptAuth();
|
||||
expect(res).toBe(requestRes);
|
||||
expect(doRequest).toBeCalledTimes(1);
|
||||
expect(stateUpdated).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should make a request if no authdata is provided", function() {
|
||||
it("should handle auth errcode presence ", async () => {
|
||||
const doRequest = jest.fn();
|
||||
const stateUpdated = jest.fn();
|
||||
|
||||
const ia = new InteractiveAuth({
|
||||
matrixClient: getFakeClient(),
|
||||
doRequest: doRequest,
|
||||
stateUpdated: stateUpdated,
|
||||
requestEmailToken: jest.fn(),
|
||||
authData: {
|
||||
session: "sessionId",
|
||||
flows: [
|
||||
{ stages: [AuthType.Password] },
|
||||
],
|
||||
errcode: "MockError0",
|
||||
params: {
|
||||
[AuthType.Password]: { param: "aa" },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(ia.getSessionId()).toEqual("sessionId");
|
||||
expect(ia.getStageParams(AuthType.Password)).toEqual({
|
||||
param: "aa",
|
||||
});
|
||||
|
||||
// first we expect a call here
|
||||
stateUpdated.mockImplementation((stage) => {
|
||||
logger.log('aaaa');
|
||||
expect(stage).toEqual(AuthType.Password);
|
||||
ia.submitAuthDict({
|
||||
type: AuthType.Password,
|
||||
});
|
||||
});
|
||||
|
||||
// .. which should trigger a call here
|
||||
const requestRes = { "a": "b" };
|
||||
doRequest.mockImplementation(async (authData) => {
|
||||
logger.log('cccc');
|
||||
expect(authData).toEqual({
|
||||
session: "sessionId",
|
||||
type: AuthType.Password,
|
||||
});
|
||||
return requestRes;
|
||||
});
|
||||
|
||||
const res = await ia.attemptAuth();
|
||||
expect(res).toBe(requestRes);
|
||||
expect(doRequest).toBeCalledTimes(1);
|
||||
expect(stateUpdated).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should handle set emailSid for email flow", async () => {
|
||||
const doRequest = jest.fn();
|
||||
const stateUpdated = jest.fn();
|
||||
const requestEmailToken = jest.fn();
|
||||
|
||||
const ia = new InteractiveAuth({
|
||||
doRequest,
|
||||
stateUpdated,
|
||||
requestEmailToken,
|
||||
matrixClient: getFakeClient(),
|
||||
emailSid: 'myEmailSid',
|
||||
authData: {
|
||||
session: "sessionId",
|
||||
flows: [
|
||||
{ stages: [AuthType.Email, AuthType.Password] },
|
||||
],
|
||||
params: {
|
||||
[AuthType.Email]: { param: "aa" },
|
||||
[AuthType.Password]: { param: "bb" },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(ia.getSessionId()).toEqual("sessionId");
|
||||
expect(ia.getStageParams(AuthType.Email)).toEqual({
|
||||
param: "aa",
|
||||
});
|
||||
|
||||
// first we expect a call here
|
||||
stateUpdated.mockImplementation((stage) => {
|
||||
logger.log('husky');
|
||||
expect(stage).toEqual(AuthType.Email);
|
||||
ia.submitAuthDict({
|
||||
type: AuthType.Email,
|
||||
});
|
||||
});
|
||||
|
||||
// .. which should trigger a call here
|
||||
const requestRes = { "a": "b" };
|
||||
doRequest.mockImplementation(async (authData) => {
|
||||
logger.log('barfoo');
|
||||
expect(authData).toEqual({
|
||||
session: "sessionId",
|
||||
type: AuthType.Email,
|
||||
});
|
||||
return requestRes;
|
||||
});
|
||||
|
||||
const res = await ia.attemptAuth();
|
||||
expect(res).toBe(requestRes);
|
||||
expect(doRequest).toBeCalledTimes(1);
|
||||
expect(stateUpdated).toBeCalledTimes(1);
|
||||
expect(requestEmailToken).toBeCalledTimes(0);
|
||||
expect(ia.getEmailSid()).toBe("myEmailSid");
|
||||
});
|
||||
|
||||
it("should make a request if no authdata is provided", async () => {
|
||||
const doRequest = jest.fn();
|
||||
const stateUpdated = jest.fn();
|
||||
const requestEmailToken = jest.fn();
|
||||
@@ -101,7 +208,7 @@ describe("InteractiveAuth", function() {
|
||||
expect(ia.getStageParams(AuthType.Password)).toBe(undefined);
|
||||
|
||||
// first we expect a call to doRequest
|
||||
doRequest.mockImplementation(function(authData) {
|
||||
doRequest.mockImplementation((authData) => {
|
||||
logger.log("request1", authData);
|
||||
expect(authData).toEqual(null); // first request should be null
|
||||
const err = new MatrixError({
|
||||
@@ -119,7 +226,7 @@ describe("InteractiveAuth", function() {
|
||||
|
||||
// .. which should be followed by a call to stateUpdated
|
||||
const requestRes = { "a": "b" };
|
||||
stateUpdated.mockImplementation(function(stage) {
|
||||
stateUpdated.mockImplementation((stage) => {
|
||||
expect(stage).toEqual(AuthType.Password);
|
||||
expect(ia.getSessionId()).toEqual("sessionId");
|
||||
expect(ia.getStageParams(AuthType.Password)).toEqual({
|
||||
@@ -127,13 +234,13 @@ describe("InteractiveAuth", function() {
|
||||
});
|
||||
|
||||
// submitAuthDict should trigger another call to doRequest
|
||||
doRequest.mockImplementation(function(authData) {
|
||||
doRequest.mockImplementation(async (authData) => {
|
||||
logger.log("request2", authData);
|
||||
expect(authData).toEqual({
|
||||
session: "sessionId",
|
||||
type: AuthType.Password,
|
||||
});
|
||||
return Promise.resolve(requestRes);
|
||||
return requestRes;
|
||||
});
|
||||
|
||||
ia.submitAuthDict({
|
||||
@@ -141,14 +248,76 @@ describe("InteractiveAuth", function() {
|
||||
});
|
||||
});
|
||||
|
||||
return ia.attemptAuth().then(function(res) {
|
||||
expect(res).toBe(requestRes);
|
||||
expect(doRequest).toBeCalledTimes(2);
|
||||
expect(stateUpdated).toBeCalledTimes(1);
|
||||
});
|
||||
const res = await ia.attemptAuth();
|
||||
expect(res).toBe(requestRes);
|
||||
expect(doRequest).toBeCalledTimes(2);
|
||||
expect(stateUpdated).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should start an auth stage and reject if no auth flow", function() {
|
||||
it("should make a request if authdata is null", async () => {
|
||||
const doRequest = jest.fn();
|
||||
const stateUpdated = jest.fn();
|
||||
const requestEmailToken = jest.fn();
|
||||
|
||||
const ia = new InteractiveAuth({
|
||||
authData: null,
|
||||
matrixClient: getFakeClient(),
|
||||
stateUpdated,
|
||||
doRequest,
|
||||
requestEmailToken,
|
||||
});
|
||||
|
||||
expect(ia.getSessionId()).toBe(undefined);
|
||||
expect(ia.getStageParams(AuthType.Password)).toBe(undefined);
|
||||
|
||||
// first we expect a call to doRequest
|
||||
doRequest.mockImplementation((authData) => {
|
||||
logger.log("request1", authData);
|
||||
expect(authData).toEqual(null); // first request should be null
|
||||
const err = new MatrixError({
|
||||
session: "sessionId",
|
||||
flows: [
|
||||
{ stages: [AuthType.Password] },
|
||||
],
|
||||
params: {
|
||||
[AuthType.Password]: { param: "aa" },
|
||||
},
|
||||
});
|
||||
err.httpStatus = 401;
|
||||
throw err;
|
||||
});
|
||||
|
||||
// .. which should be followed by a call to stateUpdated
|
||||
const requestRes = { "a": "b" };
|
||||
stateUpdated.mockImplementation((stage) => {
|
||||
expect(stage).toEqual(AuthType.Password);
|
||||
expect(ia.getSessionId()).toEqual("sessionId");
|
||||
expect(ia.getStageParams(AuthType.Password)).toEqual({
|
||||
param: "aa",
|
||||
});
|
||||
|
||||
// submitAuthDict should trigger another call to doRequest
|
||||
doRequest.mockImplementation(async (authData) => {
|
||||
logger.log("request2", authData);
|
||||
expect(authData).toEqual({
|
||||
session: "sessionId",
|
||||
type: AuthType.Password,
|
||||
});
|
||||
return requestRes;
|
||||
});
|
||||
|
||||
ia.submitAuthDict({
|
||||
type: AuthType.Password,
|
||||
});
|
||||
});
|
||||
|
||||
const res = await ia.attemptAuth();
|
||||
expect(res).toBe(requestRes);
|
||||
expect(doRequest).toBeCalledTimes(2);
|
||||
expect(stateUpdated).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should start an auth stage and reject if no auth flow", async () => {
|
||||
const doRequest = jest.fn();
|
||||
const stateUpdated = jest.fn();
|
||||
const requestEmailToken = jest.fn();
|
||||
@@ -160,7 +329,7 @@ describe("InteractiveAuth", function() {
|
||||
requestEmailToken,
|
||||
});
|
||||
|
||||
doRequest.mockImplementation(function(authData) {
|
||||
doRequest.mockImplementation((authData) => {
|
||||
logger.log("request1", authData);
|
||||
expect(authData).toEqual(null); // first request should be null
|
||||
const err = new MatrixError({
|
||||
@@ -174,9 +343,108 @@ describe("InteractiveAuth", function() {
|
||||
throw err;
|
||||
});
|
||||
|
||||
return ia.attemptAuth().catch(function(error) {
|
||||
expect(error.message).toBe('No appropriate authentication flow found');
|
||||
await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(
|
||||
new Error('No appropriate authentication flow found'),
|
||||
);
|
||||
});
|
||||
|
||||
it("should start an auth stage and reject if no auth flow but has session", async () => {
|
||||
const doRequest = jest.fn();
|
||||
const stateUpdated = jest.fn();
|
||||
const requestEmailToken = jest.fn();
|
||||
|
||||
const ia = new InteractiveAuth({
|
||||
matrixClient: getFakeClient(),
|
||||
doRequest,
|
||||
stateUpdated,
|
||||
requestEmailToken,
|
||||
authData: {
|
||||
},
|
||||
sessionId: "sessionId",
|
||||
});
|
||||
|
||||
doRequest.mockImplementation((authData) => {
|
||||
logger.log("request1", authData);
|
||||
expect(authData).toEqual({ "session": "sessionId" }); // has existing sessionId
|
||||
const err = new MatrixError({
|
||||
session: "sessionId",
|
||||
flows: [],
|
||||
params: {
|
||||
[AuthType.Password]: { param: "aa" },
|
||||
},
|
||||
error: "Mock Error 1",
|
||||
errcode: "MOCKERR1",
|
||||
});
|
||||
err.httpStatus = 401;
|
||||
throw err;
|
||||
});
|
||||
|
||||
await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(
|
||||
new Error('No appropriate authentication flow found'),
|
||||
);
|
||||
});
|
||||
|
||||
it("should handle unexpected error types without data propery set", async () => {
|
||||
const doRequest = jest.fn();
|
||||
const stateUpdated = jest.fn();
|
||||
const requestEmailToken = jest.fn();
|
||||
|
||||
const ia = new InteractiveAuth({
|
||||
matrixClient: getFakeClient(),
|
||||
doRequest,
|
||||
stateUpdated,
|
||||
requestEmailToken,
|
||||
authData: {
|
||||
session: "sessionId",
|
||||
},
|
||||
});
|
||||
|
||||
doRequest.mockImplementation((authData) => {
|
||||
logger.log("request1", authData);
|
||||
expect(authData).toEqual({ "session": "sessionId" }); // has existing sessionId
|
||||
const err = new Error('myerror');
|
||||
(err as any).httpStatus = 401;
|
||||
throw err;
|
||||
});
|
||||
|
||||
await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(
|
||||
new Error("myerror"),
|
||||
);
|
||||
});
|
||||
|
||||
it("should allow dummy auth", async () => {
|
||||
const doRequest = jest.fn();
|
||||
const stateUpdated = jest.fn();
|
||||
const requestEmailToken = jest.fn();
|
||||
|
||||
const ia = new InteractiveAuth({
|
||||
matrixClient: getFakeClient(),
|
||||
doRequest,
|
||||
stateUpdated,
|
||||
requestEmailToken,
|
||||
authData: {
|
||||
session: 'sessionId',
|
||||
flows: [
|
||||
{ stages: [AuthType.Dummy] },
|
||||
],
|
||||
params: {},
|
||||
},
|
||||
});
|
||||
|
||||
const requestRes = { "a": "b" };
|
||||
doRequest.mockImplementation((authData) => {
|
||||
logger.log("request1", authData);
|
||||
expect(authData).toEqual({
|
||||
session: "sessionId",
|
||||
type: AuthType.Dummy,
|
||||
});
|
||||
return requestRes;
|
||||
});
|
||||
|
||||
const res = await ia.attemptAuth();
|
||||
expect(res).toBe(requestRes);
|
||||
expect(doRequest).toBeCalledTimes(1);
|
||||
expect(stateUpdated).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
describe("requestEmailToken", () => {
|
||||
@@ -247,7 +515,7 @@ describe("InteractiveAuth", function() {
|
||||
doRequest, stateUpdated, requestEmailToken,
|
||||
});
|
||||
|
||||
expect(async () => await ia.requestEmailToken()).rejects.toThrowError("unspecific network error");
|
||||
await expect(ia.requestEmailToken.bind(ia)).rejects.toThrowError("unspecific network error");
|
||||
});
|
||||
|
||||
it("only starts one request at a time", async () => {
|
||||
|
Reference in New Issue
Block a user