mirror of
https://github.com/element-hq/element-web
synced 2024-11-25 18:55:58 +03:00
Move update tests to Cypress (#8716)
* Move update tests to Cypress * Fix /version intercept to account for cachebuster
This commit is contained in:
parent
eaace4b4d1
commit
af6ded3b0b
4 changed files with 53 additions and 124 deletions
53
cypress/integration/8-update/update.spec.ts
Normal file
53
cypress/integration/8-update/update.spec.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2022 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.
|
||||
*/
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import { SynapseInstance } from "../../plugins/synapsedocker";
|
||||
|
||||
describe("Update", () => {
|
||||
let synapse: SynapseInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.startSynapse("default").then(data => {
|
||||
synapse = data;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cy.stopSynapse(synapse);
|
||||
});
|
||||
|
||||
it("should navigate to ?updated=$VERSION if realises it is immediately out of date on load", () => {
|
||||
const NEW_VERSION = "some-new-version";
|
||||
|
||||
cy.intercept("/version*", {
|
||||
statusCode: 200,
|
||||
body: NEW_VERSION,
|
||||
headers: {
|
||||
"Content-Type": "test/plain",
|
||||
},
|
||||
}).as("version");
|
||||
|
||||
cy.initTestUser(synapse, "Ursa");
|
||||
|
||||
cy.wait("@version");
|
||||
cy.url().should("contain", "updated=" + NEW_VERSION).then(href => {
|
||||
const url = new URL(href);
|
||||
expect(url.searchParams.get("updated")).to.equal(NEW_VERSION);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -27,7 +27,6 @@ import { RestMultiSession } from "./rest/multi";
|
|||
import { RestSession } from "./rest/session";
|
||||
import { stickerScenarios } from './scenarios/sticker';
|
||||
import { userViewScenarios } from "./scenarios/user-view";
|
||||
import { updateScenarios } from "./scenarios/update";
|
||||
|
||||
export async function scenario(createSession: (s: string) => Promise<ElementSession>,
|
||||
restCreator: RestSessionCreator): Promise<void> {
|
||||
|
@ -63,10 +62,6 @@ export async function scenario(createSession: (s: string) => Promise<ElementSess
|
|||
// closing them as we go rather than leaving them all open until the end).
|
||||
const stickerSession = await createSession("sally");
|
||||
await stickerScenarios("sally", "ilikestickers", stickerSession, restCreator);
|
||||
|
||||
// Create a new window to test app auto-updating
|
||||
const updateSession = await createSession("update");
|
||||
await updateScenarios(updateSession);
|
||||
}
|
||||
|
||||
async function createRestUsers(restCreator: RestSessionCreator): Promise<RestMultiSession> {
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 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 { HTTPRequest } from "puppeteer";
|
||||
import { strict as assert } from 'assert';
|
||||
|
||||
import { ElementSession } from "../session";
|
||||
|
||||
const NEW_VERSION = "some-new-version";
|
||||
|
||||
async function mockVersionHTTPResponse(session: ElementSession) {
|
||||
// Mock the HTTP response to return a new version to trigger auto-update behaviour
|
||||
await session.page.setRequestInterception(true);
|
||||
session.page.on('request', (request: HTTPRequest) => {
|
||||
if (request.isInterceptResolutionHandled()) return;
|
||||
const url = new URL(request.url());
|
||||
if (url.pathname === "/version") {
|
||||
request.respond({
|
||||
contentType: "text/html",
|
||||
status: 200,
|
||||
body: NEW_VERSION,
|
||||
});
|
||||
} else {
|
||||
request.continue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateScenarios(session: ElementSession) {
|
||||
// Mock the HTTP response to return a newer version, then wait for the page to reload in response
|
||||
await mockVersionHTTPResponse(session);
|
||||
await session.goto(session.url('/'));
|
||||
await session.waitForReload();
|
||||
const newUrl = new URL(session.page.url());
|
||||
assert.equal(newUrl.searchParams.get("updated"), NEW_VERSION);
|
||||
}
|
|
@ -23,10 +23,6 @@ import { delay, serializeLog } from './util';
|
|||
|
||||
const DEFAULT_TIMEOUT = 20000;
|
||||
|
||||
interface XHRLogger {
|
||||
logs: () => string;
|
||||
}
|
||||
|
||||
export class ElementSession {
|
||||
readonly consoleLog: LogBuffer<puppeteer.ConsoleMessage>;
|
||||
readonly networkLog: LogBuffer<puppeteer.HTTPRequest>;
|
||||
|
@ -80,10 +76,6 @@ export class ElementSession {
|
|||
return this.getElementProperty(field, 'innerText');
|
||||
}
|
||||
|
||||
public getOuterHTML(field: puppeteer.ElementHandle): Promise<string> {
|
||||
return this.getElementProperty(field, 'outerHTML');
|
||||
}
|
||||
|
||||
public isChecked(field: puppeteer.ElementHandle): Promise<string> {
|
||||
return this.getElementProperty(field, 'checked');
|
||||
}
|
||||
|
@ -96,29 +88,6 @@ export class ElementSession {
|
|||
return this.networkLog.buffer;
|
||||
}
|
||||
|
||||
public logXHRRequests(): XHRLogger {
|
||||
let buffer = "";
|
||||
this.page.on('requestfinished', async (req) => {
|
||||
const type = req.resourceType();
|
||||
const response = await req.response();
|
||||
//if (type === 'xhr' || type === 'fetch') {
|
||||
buffer += `${type} ${response.status()} ${req.method()} ${req.url()} \n`;
|
||||
// if (req.method() === "POST") {
|
||||
// buffer += " Post data: " + req.postData();
|
||||
// }
|
||||
//}
|
||||
});
|
||||
return {
|
||||
logs() {
|
||||
return buffer;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public async printElements(label: string, elements: puppeteer.ElementHandle[]): Promise<void> {
|
||||
console.log(label, await Promise.all(elements.map(this.getOuterHTML)));
|
||||
}
|
||||
|
||||
public async replaceInputText(input: puppeteer.ElementHandle, text: string): Promise<void> {
|
||||
// click 3 times to select all text
|
||||
await input.click({ clickCount: 3 });
|
||||
|
@ -149,45 +118,6 @@ export class ElementSession {
|
|||
return await this.page.$$(selector);
|
||||
}
|
||||
|
||||
public waitForReload(): Promise<void> {
|
||||
const timeout = DEFAULT_TIMEOUT;
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
this.page.off('domcontentloaded', callback);
|
||||
reject(new Error(`timeout of ${timeout}ms for waitForReload elapsed`));
|
||||
}, timeout);
|
||||
|
||||
const callback = async () => {
|
||||
clearTimeout(timeoutHandle);
|
||||
resolve();
|
||||
};
|
||||
|
||||
this.page.once('domcontentloaded', callback);
|
||||
});
|
||||
}
|
||||
|
||||
public waitForNewPage(): Promise<void> {
|
||||
const timeout = DEFAULT_TIMEOUT;
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
this.browser.off('targetcreated', callback);
|
||||
reject(new Error(`timeout of ${timeout}ms for waitForNewPage elapsed`));
|
||||
}, timeout);
|
||||
|
||||
const callback = async (target) => {
|
||||
if (target.type() !== 'page') {
|
||||
return;
|
||||
}
|
||||
this.browser.off('targetcreated', callback);
|
||||
clearTimeout(timeoutHandle);
|
||||
const page = await target.page();
|
||||
resolve(page);
|
||||
};
|
||||
|
||||
this.browser.on('targetcreated', callback);
|
||||
});
|
||||
}
|
||||
|
||||
/** wait for a /sync request started after this call that gets a 200 response */
|
||||
public async waitForNextSuccessfulSync(): Promise<void> {
|
||||
const syncUrls = [];
|
||||
|
|
Loading…
Reference in a new issue