Skip to content

Commit

Permalink
Add e2e test for dummy projects (#22)
Browse files Browse the repository at this point in the history
# Motivation

Main motivation is to avoid breaking the dummy relying party or issuer.

In this PR,
* I set up an e2e test using the dummy RP requesting a credential to the
issuer.
* Add the test to the CI pipeline.

# Changes

* Add a new project for the e2e test: dummy-e2e.

# Tests

* Add test ids to the relying party HTML.
* Add internet identity to dfx.json and a dummy candid file.
* Add rust-toolchain.toml
* Add a Github workflow to prepare the environment and run the e2e
tests.

# Todos

- [ ] Add entry to changelog (if necessary). NOT NECESSARY, no changes
in the SDK projects.
  • Loading branch information
lmuntaner authored Jun 7, 2024
1 parent 0e8e2b2 commit 2e4d7c0
Show file tree
Hide file tree
Showing 11 changed files with 335 additions and 5 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Playwright Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install dependencies
working-directory: dummy-e2e
run: npm ci
- name: Install ic-wasm
run: cargo install ic-wasm --version 0.3.5
- name: Install Playwright Browsers
working-directory: dummy-e2e
run: npx playwright install --with-deps
- name: Install dfx
uses: dfinity/setup-dfx@main
- name: Start local replica
run: dfx start --background
- name: Deploy canisters
run: dfx deploy
- name: Prepare environment variables
working-directory: dummy-e2e
run: ./create-env-vars.sh
- name: Run Playwright tests
working-directory: dummy-e2e
run: npm run e2e
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
- name: Stop local replica
run: dfx stop
5 changes: 5 additions & 0 deletions dfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
"wasm": "./dummy-issuer/dummy_issuer.wasm.gz",
"build": "./dummy-issuer/build.sh",
"shrink": false
},
"internet_identity": {
"type": "custom",
"wasm": "https://github.com/dfinity/internet-identity/releases/download/release-2024-04-05/internet_identity_dev.wasm.gz",
"candid": "https://github.com/dfinity/internet-identity/releases/download/release-2024-04-05/internet_identity.did"
}
}
}
5 changes: 5 additions & 0 deletions dummy-e2e/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
17 changes: 17 additions & 0 deletions dummy-e2e/create-env-vars.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# This script creates a .env file with the necessary environment variables
# for the local environment to run the tests.
# Needs to be executed within the same directory as the script.
ENV_FILE=${ENV_OUTPUT_FILE:-$PWD/.env}
echo "Creating .env file at $ENV_FILE"

II_CANISTER_ID=$(dfx canister id internet_identity --network local)
ISSUER_CANISTER_ID=$(dfx canister id dummy_issuer --network local)
RP_CANISTER_ID=$(dfx canister id dummy_relying_party --network local)

REPLICA_SERVER_PORT=$(dfx info webserver-port)
II_URL="http://${II_CANISTER_ID}.localhost:${REPLICA_SERVER_PORT}"
ISSUER_ORIGIN="http://${ISSUER_CANISTER_ID}.localhost:${REPLICA_SERVER_PORT}"
RP_ORIGIN="http://${RP_CANISTER_ID}.localhost:${REPLICA_SERVER_PORT}"
echo "II_URL=${II_URL}" > $ENV_FILE
echo "ISSUER_URL=${ISSUER_ORIGIN}" >> $ENV_FILE
echo "RP_URL=${RP_ORIGIN}" >> $ENV_FILE
105 changes: 105 additions & 0 deletions dummy-e2e/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions dummy-e2e/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "dummy-e2e",
"version": "0.0.1",
"description": "End to end tests for the dummy relying party and issuer.",
"scripts": {
"e2e": "playwright test"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.44.1",
"@types/node": "^20.14.2"
},
"dependencies": {
"dotenv": "^16.4.5"
}
}
38 changes: 38 additions & 0 deletions dummy-e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { defineConfig, devices } from "@playwright/test";
import dotenv from "dotenv";

dotenv.config();

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./src",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
screenshot: "only-on-failure",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "retain-on-failure",
/* Uncomment if you want to see the e2e tests running in the browser */
// headless: false,
testIdAttribute: "data-tid",
},

/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
});
37 changes: 37 additions & 0 deletions dummy-e2e/src/utils/sigin-in-user.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { expect, type BrowserContext, type Page } from "@playwright/test";

export const signInWithNewUser = async ({
page,
context,
}: {
page: Page;
context: BrowserContext;
}): Promise<number> => {
const iiPagePromise = context.waitForEvent("page");

await page.locator("[data-tid=login-button]").click();

const iiPage = await iiPagePromise;
await expect(iiPage).toHaveTitle("Internet Identity");

await iiPage.locator("#registerButton").click();
await iiPage.locator("[data-action=construct-identity]").click();

await iiPage.locator("input#captchaInput").fill("a");
await iiPage.locator("#confirmRegisterButton").click();

try {
const anchor = await iiPage.locator("#userNumber").textContent();
await iiPage.locator("#displayUserContinue").click();
await iiPage.waitForEvent("close");
await expect(iiPage.isClosed()).toBe(true);

if (anchor === null) {
throw new Error("Anchor is null");
}
return parseInt(anchor);
} catch (err) {
console.error("Error:", err);
return -1;
}
};
44 changes: 44 additions & 0 deletions dummy-e2e/src/vc-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { test, expect } from "@playwright/test";
import { signInWithNewUser } from "./utils/sigin-in-user.utils";

const RP_URL = process.env.RP_URL ?? "";
const ISSUER_URL = process.env.ISSUER_URL ?? "";
const II_URL = process.env.II_URL ?? "";

test("user gets credential from dummy issuer within the dummy relying party", async ({
page,
context,
}) => {
await page.goto(RP_URL);
await expect(page).toHaveTitle("Dummy Relying Party");

await expect(await page.getByTestId("user-principal").isVisible()).toBe(
false
);

// Log in with a new user
await page.getByTestId("ii-url-input").fill(II_URL);

await signInWithNewUser({ page, context });

await expect(await page.getByTestId("user-principal").isVisible()).toBe(true);

// Fill credentials
await page.getByTestId("issuer-url-input").fill(ISSUER_URL);

await page.getByTestId("credential-type-input").fill("Test");

await expect(await page.getByTestId("vc-result").textContent()).toBe("-");

// Request credentials
const iiPagePromise = context.waitForEvent("page");
await page.getByTestId("request-credential-button").click();

const iiPage = await iiPagePromise;
await expect(iiPage).toHaveTitle("Internet Identity");
await iiPage.locator("[data-action=allow]").click();
await iiPage.waitForEvent("close");
await expect(iiPage.isClosed()).toBe(true);

await expect(await page.getByTestId("vc-result").textContent()).not.toBe("-");
});
Loading

0 comments on commit 2e4d7c0

Please sign in to comment.