From c616bd7a62567a2789dc0538643bd56a062b5d27 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Wed, 4 May 2022 12:07:37 +0100
Subject: [PATCH] Attempt to fix the cypress flake (#8492)
---
.../integration/1-register/register.spec.ts | 14 ++---
cypress/plugins/index.ts | 9 ++-
cypress/plugins/synapsedocker/index.ts | 13 +++--
cypress/support/index.ts | 22 +++++++-
cypress/support/synapse.ts | 55 +++++++++++++++++++
5 files changed, 95 insertions(+), 18 deletions(-)
create mode 100644 cypress/support/synapse.ts
diff --git a/cypress/integration/1-register/register.spec.ts b/cypress/integration/1-register/register.spec.ts
index f719da5547..e06d1e5f28 100644
--- a/cypress/integration/1-register/register.spec.ts
+++ b/cypress/integration/1-register/register.spec.ts
@@ -16,27 +16,25 @@ limitations under the License.
///
-import { SynapseInstance } from "../../plugins/synapsedocker/index";
+import { SynapseInstance } from "../../plugins/synapsedocker";
describe("Registration", () => {
- let synapseId;
- let synapsePort;
+ let synapse: SynapseInstance;
beforeEach(() => {
- cy.task("synapseStart", "consent").then(result => {
- synapseId = result.synapseId;
- synapsePort = result.port;
+ cy.startSynapse("consent").then(data => {
+ synapse = data;
});
cy.visit("/#/register");
});
afterEach(() => {
- cy.task("synapseStop", synapseId);
+ cy.stopSynapse(synapse);
});
it("registers an account and lands on the home screen", () => {
cy.get(".mx_ServerPicker_change", { timeout: 15000 }).click();
- cy.get(".mx_ServerPickerDialog_otherHomeserver").type(`http://localhost:${synapsePort}`);
+ cy.get(".mx_ServerPickerDialog_otherHomeserver").type(`http://localhost:${synapse.port}`);
cy.get(".mx_ServerPickerDialog_continue").click();
// wait for the dialog to go away
cy.get('.mx_ServerPickerDialog').should('not.exist');
diff --git a/cypress/plugins/index.ts b/cypress/plugins/index.ts
index db01ceceb4..9438d13606 100644
--- a/cypress/plugins/index.ts
+++ b/cypress/plugins/index.ts
@@ -16,8 +16,13 @@ limitations under the License.
///
-import { synapseDocker } from "./synapsedocker/index";
+import { synapseDocker } from "./synapsedocker";
+import PluginEvents = Cypress.PluginEvents;
+import PluginConfigOptions = Cypress.PluginConfigOptions;
-export default function(on, config) {
+/**
+ * @type {Cypress.PluginConfig}
+ */
+export default function(on: PluginEvents, config: PluginConfigOptions) {
synapseDocker(on, config);
}
diff --git a/cypress/plugins/synapsedocker/index.ts b/cypress/plugins/synapsedocker/index.ts
index 0f029e7b2e..912e99431e 100644
--- a/cypress/plugins/synapsedocker/index.ts
+++ b/cypress/plugins/synapsedocker/index.ts
@@ -22,6 +22,9 @@ import * as crypto from "crypto";
import * as childProcess from "child_process";
import * as fse from "fs-extra";
+import PluginEvents = Cypress.PluginEvents;
+import PluginConfigOptions = Cypress.PluginConfigOptions;
+
// A cypress plugins to add command to start & stop synapses in
// docker with preset templates.
@@ -130,7 +133,7 @@ async function synapseStart(template: string): Promise {
return synapses.get(synapseId);
}
-async function synapseStop(id) {
+async function synapseStop(id: string): Promise {
const synCfg = synapses.get(id);
if (!synCfg) throw new Error("Unknown synapse ID");
@@ -186,10 +189,10 @@ async function synapseStop(id) {
/**
* @type {Cypress.PluginConfig}
*/
-// eslint-disable-next-line no-unused-vars
-export function synapseDocker(on, config) {
+export function synapseDocker(on: PluginEvents, config: PluginConfigOptions) {
on("task", {
- synapseStart, synapseStop,
+ synapseStart,
+ synapseStop,
});
on("after:spec", async (spec) => {
@@ -197,7 +200,7 @@ export function synapseDocker(on, config) {
// This is on the theory that we should avoid re-using synapse
// instances between spec runs: they should be cheap enough to
// start that we can have a separate one for each spec run or even
- // test. If we accidentally re-use synapses, we could inadvertantly
+ // test. If we accidentally re-use synapses, we could inadvertently
// make our tests depend on each other.
for (const synId of synapses.keys()) {
console.warn(`Cleaning up synapse ID ${synId} after ${spec.name}`);
diff --git a/cypress/support/index.ts b/cypress/support/index.ts
index 9901ef4cb8..289319fe97 100644
--- a/cypress/support/index.ts
+++ b/cypress/support/index.ts
@@ -1,3 +1,19 @@
-// Empty file to prevent cypress from recreating a helpful example
-// file on every run (their example file doesn't use semicolons and
-// so fails our lint rules).
+/*
+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 "./synapse";
diff --git a/cypress/support/synapse.ts b/cypress/support/synapse.ts
new file mode 100644
index 0000000000..f49f55a19d
--- /dev/null
+++ b/cypress/support/synapse.ts
@@ -0,0 +1,55 @@
+/*
+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 Chainable = Cypress.Chainable;
+import AUTWindow = Cypress.AUTWindow;
+import { SynapseInstance } from "../plugins/synapsedocker";
+
+declare global {
+ // eslint-disable-next-line @typescript-eslint/no-namespace
+ namespace Cypress {
+ interface Chainable {
+ /**
+ * Start a synapse instance with a given config template.
+ * @param template path to template within cypress/plugins/synapsedocker/template/ directory.
+ */
+ startSynapse(template: string): Chainable;
+ /**
+ * Custom command wrapping task:synapseStop whilst preventing uncaught exceptions
+ * for if Synapse stopping races with the app's background sync loop.
+ * @param synapse the synapse instance returned by startSynapse
+ */
+ stopSynapse(synapse: SynapseInstance): Chainable;
+ }
+ }
+}
+
+function startSynapse(template: string): Chainable {
+ return cy.task("synapseStart", template);
+}
+
+function stopSynapse(synapse: SynapseInstance): Chainable {
+ // Navigate away from app to stop the background network requests which will race with Synapse shutting down
+ return cy.window().then((win) => {
+ win.location.href = 'about:blank';
+ cy.task("synapseStop", synapse.synapseId);
+ });
+}
+
+Cypress.Commands.add("startSynapse", startSynapse);
+Cypress.Commands.add("stopSynapse", stopSynapse);