Cypress test for QR code display (#11240)
This commit is contained in:
parent
2cfbd73cd3
commit
46c12a808f
3 changed files with 69 additions and 0 deletions
|
@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import jsQR from "jsqr";
|
||||||
|
|
||||||
import type { VerificationRequest, Verifier } from "matrix-js-sdk/src/crypto-api/verification";
|
import type { VerificationRequest, Verifier } from "matrix-js-sdk/src/crypto-api/verification";
|
||||||
import { CypressBot } from "../../support/bot";
|
import { CypressBot } from "../../support/bot";
|
||||||
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
||||||
|
@ -21,6 +23,24 @@ import { emitPromise } from "../../support/util";
|
||||||
import { checkDeviceIsCrossSigned, doTwoWaySasVerification, logIntoElement, waitForVerificationRequest } from "./utils";
|
import { checkDeviceIsCrossSigned, doTwoWaySasVerification, logIntoElement, waitForVerificationRequest } from "./utils";
|
||||||
import { getToast } from "../../support/toasts";
|
import { getToast } from "../../support/toasts";
|
||||||
|
|
||||||
|
/** Render a data URL and return the rendered image data */
|
||||||
|
async function renderQRCode(dataUrl: string): Promise<ImageData> {
|
||||||
|
// create a new image and set the source to the data url
|
||||||
|
const img = new Image();
|
||||||
|
await new Promise((r) => {
|
||||||
|
img.onload = r;
|
||||||
|
img.src = dataUrl;
|
||||||
|
});
|
||||||
|
|
||||||
|
// draw the image on a canvas
|
||||||
|
const myCanvas = new OffscreenCanvas(256, 256);
|
||||||
|
const ctx = myCanvas.getContext("2d");
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
|
||||||
|
// read the image data
|
||||||
|
return ctx.getImageData(0, 0, myCanvas.width, myCanvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
describe("Device verification", () => {
|
describe("Device verification", () => {
|
||||||
let aliceBotClient: CypressBot;
|
let aliceBotClient: CypressBot;
|
||||||
let homeserver: HomeserverInstance;
|
let homeserver: HomeserverInstance;
|
||||||
|
@ -91,6 +111,49 @@ describe("Device verification", () => {
|
||||||
checkDeviceIsCrossSigned();
|
checkDeviceIsCrossSigned();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Verify device during login with QR code", () => {
|
||||||
|
logIntoElement(homeserver.baseUrl, aliceBotClient.getUserId(), aliceBotClient.__cypress_password);
|
||||||
|
|
||||||
|
// Launch the verification request between alice and the bot
|
||||||
|
initiateAliceVerificationRequest();
|
||||||
|
|
||||||
|
cy.get(".mx_InfoDialog").within(() => {
|
||||||
|
cy.get('[alt="QR Code"]').then((qrCode) => {
|
||||||
|
/* the bot scans the QR code */
|
||||||
|
cy.get<VerificationRequest>("@verificationRequest")
|
||||||
|
.then(async (request: VerificationRequest) => {
|
||||||
|
// because I don't know how to scrape the imagedata from the cypress browser window,
|
||||||
|
// we extract the data url and render it to a new canvas.
|
||||||
|
const imageData = await renderQRCode(qrCode.attr("src"));
|
||||||
|
|
||||||
|
// now we can decode the QR code...
|
||||||
|
const result = jsQR(imageData.data, imageData.width, imageData.height);
|
||||||
|
|
||||||
|
// ... and feed it into the verification request.
|
||||||
|
return await request.scanQRCode(new Uint8Array(result.binaryData));
|
||||||
|
})
|
||||||
|
.as("verifier");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Confirm that the bot user scanned successfully
|
||||||
|
cy.findByText("Almost there! Is your other device showing the same shield?");
|
||||||
|
cy.findByRole("button", { name: "Yes" }).click();
|
||||||
|
|
||||||
|
cy.findByRole("button", { name: "Got it" }).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// wait for the bot to see we have finished
|
||||||
|
cy.get<Verifier>("@verifier").then(async (verifier) => {
|
||||||
|
await verifier.verify();
|
||||||
|
});
|
||||||
|
|
||||||
|
// the bot uploads the signatures asynchronously, so wait for that to happen
|
||||||
|
cy.wait(1000);
|
||||||
|
|
||||||
|
// Check that our device is now cross-signed
|
||||||
|
checkDeviceIsCrossSigned();
|
||||||
|
});
|
||||||
|
|
||||||
it("Verify device during login with Security Phrase", () => {
|
it("Verify device during login with Security Phrase", () => {
|
||||||
logIntoElement(homeserver.baseUrl, aliceBotClient.getUserId(), aliceBotClient.__cypress_password);
|
logIntoElement(homeserver.baseUrl, aliceBotClient.getUserId(), aliceBotClient.__cypress_password);
|
||||||
|
|
||||||
|
|
|
@ -203,6 +203,7 @@
|
||||||
"jest-environment-jsdom": "^29.2.2",
|
"jest-environment-jsdom": "^29.2.2",
|
||||||
"jest-mock": "^29.2.2",
|
"jest-mock": "^29.2.2",
|
||||||
"jest-raw-loader": "^1.0.1",
|
"jest-raw-loader": "^1.0.1",
|
||||||
|
"jsqr": "^1.4.0",
|
||||||
"matrix-mock-request": "^2.5.0",
|
"matrix-mock-request": "^2.5.0",
|
||||||
"matrix-web-i18n": "^1.4.0",
|
"matrix-web-i18n": "^1.4.0",
|
||||||
"mocha-junit-reporter": "^2.2.0",
|
"mocha-junit-reporter": "^2.2.0",
|
||||||
|
|
|
@ -6497,6 +6497,11 @@ jsprim@^2.0.2:
|
||||||
json-schema "0.4.0"
|
json-schema "0.4.0"
|
||||||
verror "1.10.0"
|
verror "1.10.0"
|
||||||
|
|
||||||
|
jsqr@^1.4.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/jsqr/-/jsqr-1.4.0.tgz#8efb8d0a7cc6863cb6d95116b9069123ce9eb2d1"
|
||||||
|
integrity sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==
|
||||||
|
|
||||||
"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3:
|
"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3:
|
||||||
version "3.3.3"
|
version "3.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea"
|
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea"
|
||||||
|
|
Loading…
Reference in a new issue