Cypress tests for soft logout (#11402)

This commit is contained in:
Richard van der Hoff 2023-08-16 08:40:09 +01:00 committed by GitHub
parent 373a34c3d1
commit 4f138ed041
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 194 additions and 28 deletions

View file

@ -17,6 +17,7 @@ limitations under the License.
/// <reference types="cypress" /> /// <reference types="cypress" />
import { HomeserverInstance } from "../../plugins/utils/homeserver"; import { HomeserverInstance } from "../../plugins/utils/homeserver";
import { doTokenRegistration } from "./utils";
describe("Login", () => { describe("Login", () => {
let homeserver: HomeserverInstance; let homeserver: HomeserverInstance;
@ -93,7 +94,6 @@ describe("Login", () => {
}) })
.then((data) => { .then((data) => {
homeserver = data; homeserver = data;
cy.visit("/#/login");
}); });
}); });
@ -108,33 +108,7 @@ describe("Login", () => {
// If you are using ufw, try something like: // If you are using ufw, try something like:
// sudo ufw allow in on docker0 // sudo ufw allow in on docker0
// //
cy.findByRole("button", { name: "Edit" }).click(); doTokenRegistration(homeserver.baseUrl);
cy.findByRole("textbox", { name: "Other homeserver" }).type(homeserver.baseUrl);
cy.findByRole("button", { name: "Continue" }).click();
// wait for the dialog to go away
cy.get(".mx_ServerPickerDialog").should("not.exist");
// click on "Continue with OAuth test"
cy.findByRole("button", { name: "Continue with OAuth test" }).click();
// wait for the Test OAuth Page to load
cy.findByText("Test OAuth page");
// click the submit button
cy.findByRole("button", { name: "Submit" }).click();
// Synapse prompts us to pick a user ID
cy.findByRole("heading", { name: "Create your account" });
cy.findByRole("textbox", { name: "Username (required)" }).type("alice");
// wait for username validation to start, and complete
cy.wait(50);
cy.get("#field-username-output").should("have.value", "");
cy.findByRole("button", { name: "Continue" }).click();
// Synapse prompts us to grant permission to Element
cy.findByRole("heading", { name: "Continue to your account" });
cy.findByRole("link", { name: "Continue" }).click();
// Eventually, we should end up at the home screen. // Eventually, we should end up at the home screen.
cy.url().should("contain", "/#/home", { timeout: 30000 }); cy.url().should("contain", "/#/home", { timeout: 30000 });

View file

@ -0,0 +1,143 @@
/*
Copyright 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { HomeserverInstance } from "../../plugins/utils/homeserver";
import { UserCredentials } from "../../support/login";
import { doTokenRegistration } from "./utils";
describe("Soft logout", () => {
let homeserver: HomeserverInstance;
beforeEach(() => {
cy.task("startOAuthServer")
.then((oAuthServerPort: number) => {
return cy.startHomeserver({ template: "default", oAuthServerPort });
})
.then((data) => {
homeserver = data;
});
});
afterEach(() => {
cy.stopHomeserver(homeserver);
});
describe("with password user", () => {
let testUserCreds: UserCredentials;
beforeEach(() => {
cy.initTestUser(homeserver, "Alice").then((creds) => {
testUserCreds = creds;
});
});
it("shows the soft-logout page when a request fails, and allows a re-login", () => {
interceptRequestsWithSoftLogout();
cy.findByText("You're signed out");
cy.findByPlaceholderText("Password").type(testUserCreds.password).type("{enter}");
// back to the welcome page
cy.url().should("contain", "/#/home", { timeout: 30000 });
cy.findByRole("heading", { name: "Welcome Alice" });
});
it("still shows the soft-logout page when the page is reloaded after a soft-logout", () => {
interceptRequestsWithSoftLogout();
cy.findByText("You're signed out");
cy.reload();
cy.findByText("You're signed out");
});
});
describe("with SSO user", () => {
beforeEach(() => {
doTokenRegistration(homeserver.baseUrl);
// Eventually, we should end up at the home screen.
cy.url().should("contain", "/#/home", { timeout: 30000 });
cy.findByRole("heading", { name: "Welcome Alice" });
});
it("shows the soft-logout page when a request fails, and allows a re-login", () => {
// there is a bug in Element which means this only actually works if there is an app reload between
// the token login and the soft-logout: https://github.com/vector-im/element-web/issues/25957
cy.reload();
cy.findByRole("heading", { name: "Welcome Alice" });
interceptRequestsWithSoftLogout();
cy.findByText("You're signed out");
cy.findByRole("button", { name: "Continue with OAuth test" }).click();
// click the submit button
cy.findByRole("button", { name: "Submit" }).click();
// Synapse prompts us to grant permission to Element
cy.findByRole("heading", { name: "Continue to your account" });
cy.findByRole("link", { name: "Continue" }).click();
// back to the welcome page
cy.url().should("contain", "/#/home", { timeout: 30000 });
cy.findByRole("heading", { name: "Welcome Alice" });
});
});
});
/**
* Intercept calls to /sync and have them fail with a soft-logout
*
* Any further requests to /sync with the same access token are blocked.
*/
function interceptRequestsWithSoftLogout(): void {
let expiredAccessToken: string | null = null;
cy.intercept(
{
pathname: "/_matrix/client/*/sync",
},
(req) => {
const accessToken = req.headers["authorization"] as string;
// on the first request, record the access token
if (!expiredAccessToken) {
console.log(`Soft-logout on access token ${accessToken}`);
expiredAccessToken = accessToken;
}
// now, if the access token on this request matches the expired one, block it
if (expiredAccessToken && accessToken === expiredAccessToken) {
console.log(`Intercepting request with soft-logged-out access token`);
req.reply({
statusCode: 401,
body: {
errcode: "M_UNKNOWN_TOKEN",
error: "Soft logout",
soft_logout: true,
},
});
return;
}
// otherwise, pass through as normal
req.continue();
},
);
// do something to make the active /sync return: create a new room
cy.getClient().then((client) => {
// don't wait for this to complete: it probably won't, because of the broken sync
return client.createRoom({});
});
}

View file

@ -0,0 +1,49 @@
/*
Copyright 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/** Visit the login page, choose to log in with "OAuth test", register a new account, and redirect back to Element
*/
export function doTokenRegistration(homeserverUrl: string) {
cy.visit("/#/login");
cy.findByRole("button", { name: "Edit" }).click();
cy.findByRole("textbox", { name: "Other homeserver" }).type(homeserverUrl);
cy.findByRole("button", { name: "Continue" }).click();
// wait for the dialog to go away
cy.get(".mx_ServerPickerDialog").should("not.exist");
// click on "Continue with OAuth test"
cy.findByRole("button", { name: "Continue with OAuth test" }).click();
// wait for the Test OAuth Page to load
cy.findByText("Test OAuth page");
// click the submit button
cy.findByRole("button", { name: "Submit" }).click();
// Synapse prompts us to pick a user ID
cy.findByRole("heading", { name: "Create your account" });
cy.findByRole("textbox", { name: "Username (required)" }).type("alice");
// wait for username validation to start, and complete
cy.wait(50);
cy.get("#field-username-output").should("have.value", "");
cy.findByRole("button", { name: "Continue" }).click();
// Synapse prompts us to grant permission to Element
cy.findByRole("heading", { name: "Continue to your account" });
cy.findByRole("link", { name: "Continue" }).click();
}