mirror of https://github.com/vector-im/riot-web
Move update tests to Cypress (#8716)
* Move update tests to Cypress * Fix /version intercept to account for cachebustert3chguy/dedup-icons-17oct
parent
eaace4b4d1
commit
af6ded3b0b
|
@ -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 { RestSession } from "./rest/session";
|
||||||
import { stickerScenarios } from './scenarios/sticker';
|
import { stickerScenarios } from './scenarios/sticker';
|
||||||
import { userViewScenarios } from "./scenarios/user-view";
|
import { userViewScenarios } from "./scenarios/user-view";
|
||||||
import { updateScenarios } from "./scenarios/update";
|
|
||||||
|
|
||||||
export async function scenario(createSession: (s: string) => Promise<ElementSession>,
|
export async function scenario(createSession: (s: string) => Promise<ElementSession>,
|
||||||
restCreator: RestSessionCreator): Promise<void> {
|
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).
|
// closing them as we go rather than leaving them all open until the end).
|
||||||
const stickerSession = await createSession("sally");
|
const stickerSession = await createSession("sally");
|
||||||
await stickerScenarios("sally", "ilikestickers", stickerSession, restCreator);
|
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> {
|
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;
|
const DEFAULT_TIMEOUT = 20000;
|
||||||
|
|
||||||
interface XHRLogger {
|
|
||||||
logs: () => string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ElementSession {
|
export class ElementSession {
|
||||||
readonly consoleLog: LogBuffer<puppeteer.ConsoleMessage>;
|
readonly consoleLog: LogBuffer<puppeteer.ConsoleMessage>;
|
||||||
readonly networkLog: LogBuffer<puppeteer.HTTPRequest>;
|
readonly networkLog: LogBuffer<puppeteer.HTTPRequest>;
|
||||||
|
@ -80,10 +76,6 @@ export class ElementSession {
|
||||||
return this.getElementProperty(field, 'innerText');
|
return this.getElementProperty(field, 'innerText');
|
||||||
}
|
}
|
||||||
|
|
||||||
public getOuterHTML(field: puppeteer.ElementHandle): Promise<string> {
|
|
||||||
return this.getElementProperty(field, 'outerHTML');
|
|
||||||
}
|
|
||||||
|
|
||||||
public isChecked(field: puppeteer.ElementHandle): Promise<string> {
|
public isChecked(field: puppeteer.ElementHandle): Promise<string> {
|
||||||
return this.getElementProperty(field, 'checked');
|
return this.getElementProperty(field, 'checked');
|
||||||
}
|
}
|
||||||
|
@ -96,29 +88,6 @@ export class ElementSession {
|
||||||
return this.networkLog.buffer;
|
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> {
|
public async replaceInputText(input: puppeteer.ElementHandle, text: string): Promise<void> {
|
||||||
// click 3 times to select all text
|
// click 3 times to select all text
|
||||||
await input.click({ clickCount: 3 });
|
await input.click({ clickCount: 3 });
|
||||||
|
@ -149,45 +118,6 @@ export class ElementSession {
|
||||||
return await this.page.$$(selector);
|
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 */
|
/** wait for a /sync request started after this call that gets a 200 response */
|
||||||
public async waitForNextSuccessfulSync(): Promise<void> {
|
public async waitForNextSuccessfulSync(): Promise<void> {
|
||||||
const syncUrls = [];
|
const syncUrls = [];
|
||||||
|
|
Loading…
Reference in New Issue