Skip to content

Implement E2E tests for all possible new authorization flows. #3110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9791cfe
Implement E2E tests for all possible new authorization flows.
sea-snake Jun 2, 2025
7e260fc
Implement E2E tests for all possible new authorization flows.
sea-snake Jun 2, 2025
bf5601c
Merge branch 'main' into sea-snake/new-authorization-flows-e2e
sea-snake Jun 2, 2025
6b4a300
Avoid redirect when wiping storage.
sea-snake Jun 2, 2025
3d31683
Merge remote-tracking branch 'origin/sea-snake/new-authorization-flow…
sea-snake Jun 2, 2025
6472cb1
Merge branch 'main' into sea-snake/new-authorization-flows-e2e
sea-snake Jun 2, 2025
2a317be
Debug flaky waitToClose
sea-snake Jun 2, 2025
cdb3b7c
Merge remote-tracking branch 'origin/sea-snake/new-authorization-flow…
sea-snake Jun 2, 2025
c7dce9e
Debug by limiting e2e tests only to new tests
sea-snake Jun 2, 2025
0355f77
WIP
sea-snake Jun 2, 2025
6772a68
Skip tests that require more advanced mocking
sea-snake Jun 4, 2025
93f7990
Revert unrelated change.
sea-snake Jun 4, 2025
2db4d2b
Verify cause behind failed e2e
sea-snake Jun 4, 2025
5a340fa
WIP
sea-snake Jun 6, 2025
259fb6e
Merge branch 'main' into sea-snake/new-authorization-flows-e2e
sea-snake Jun 16, 2025
1e80f64
Implement e2e tests for new authorize flow with playwright.
sea-snake Jun 17, 2025
f157f32
Changes from main
sea-snake Jun 17, 2025
7fc9488
Make sure playwright browsers are installed
sea-snake Jun 17, 2025
bc0eb23
Revert old e2e tests change
sea-snake Jun 17, 2025
a36b8ff
Update pipeline
sea-snake Jun 17, 2025
21e05d9
Update pipeline
sea-snake Jun 17, 2025
6adec8b
Update pipeline
sea-snake Jun 17, 2025
a73e3f0
Update pipeline
sea-snake Jun 17, 2025
87abc11
Fix e2e, redirect first and then close dialog.
sea-snake Jun 17, 2025
961b310
Archive playwright reports on failure.
sea-snake Jun 17, 2025
cdb3493
Cleanup unused functions
sea-snake Jun 17, 2025
630abe8
Cleanup unused functions
sea-snake Jun 17, 2025
e4f0bb5
Merge branch 'main' into sea-snake/new-authorization-flows-e2e
sea-snake Jun 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions .github/workflows/canister-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@
# (i.e. capitalize the first letter)
captcha_variant="Captcha$(tr '[:lower:]' '[:upper:]' <<< ${captcha_flag:0:1})${captcha_flag:1}"
# NOTE: dfx install will run the postinstall scripts from dfx.json
dfx canister install internet_identity --wasm internet_identity_test.wasm.gz --argument "(opt record { captcha_config = opt record { max_unsolved_captchas= 50:nat64; captcha_trigger = variant {Static = variant { $captcha_variant }}}; related_origins = opt vec { \"https://identity.internetcomputer.org\"; \"https://identity.ic0.app\" }; dummy_auth = opt opt record { prompt_for_index = true }})"
dfx canister install internet_identity --wasm internet_identity_test.wasm.gz --argument "(opt record { captcha_config = opt record { max_unsolved_captchas= 50:nat64; captcha_trigger = variant {Static = variant { $captcha_variant }}}; related_origins = opt vec { \"https://identity.internetcomputer.org\"; \"https://identity.ic0.app\" }})"
dfx canister install test_app --wasm demos/test-app/test_app.wasm
dfx canister install issuer --wasm demos/vc_issuer/vc_demo_issuer.wasm.gz

Expand Down Expand Up @@ -576,11 +576,103 @@
name: e2e-test-failures-${{ env.artifact_suffix }}
path: test-failures/*
if-no-files-found: ignore

e2e-playwright:
runs-on: ubuntu-latest
needs: [ cached-build, test-app-build ]
strategy:
matrix:
device: [ "desktop", "mobile" ]
shard: [ "1_3", "2_3", "3_3" ]
# Make sure that one failing test does not cancel all other matrix jobs
fail-fast: false

env:
# Suffix used for tagging artifacts
artifact_suffix: next-${{ matrix.device }}-${{ matrix.shard }}

steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node

- name: Install npm deps
run: npm ci --no-audit --no-fund

- name: Install Playwright Browsers
run: npx playwright install chromium

- uses: dfinity/setup-dfx@e50c04f104ee4285ec010f10609483cf41e4d365

# Helps with debugging
- name: Show versions
run: |
echo dfx --version
dfx --version
echo node --version
node --version

- name: "Run dfx"
run: dfx start --background --artificial-delay 0

- name: "Download II wasm"
uses: actions/download-artifact@v4
with:
name: internet_identity_test_cached.wasm.gz
path: .

- name: "Download test app wasm"
uses: actions/download-artifact@v4
with:
name: test_app.wasm
path: demos/test-app

- name: Create Canisters
run: dfx canister create --all

- name: Deploy canisters
run: |
# NOTE: dfx install will run the postinstall scripts from dfx.json
dfx canister install internet_identity --wasm internet_identity_test.wasm.gz --argument "(opt record { captcha_config = opt record { max_unsolved_captchas= 50:nat64; captcha_trigger = variant {Static = variant { CaptchaDisabled }}}; related_origins = opt vec { \"https://id.ai\" }; new_flow_origins = opt vec { \"https://id.ai\" }; dummy_auth = opt opt record { prompt_for_index = true }})"
dfx canister install test_app --wasm demos/test-app/test_app.wasm

- name: Run dev server
id: dev-server-start
run: |
TLS_DEV_SERVER=1 NO_HOT_RELOAD=1 npm run dev | tee -a > dev-server-logs.txt &
dev_server_pid=$!
echo "dev_server_pid=$dev_server_pid" >> "$GITHUB_OUTPUT"

- run: |
npx playwright test --project ${{ matrix.device }} --workers 1 --shard=$(tr <<<'${{ matrix.shard }}' -s _ /)

- name: Stop dfx
if: ${{ always() }}
run: dfx stop

- name: Stop dev server
if: ${{ always() }}
run: kill ${{ steps.dev-server-start.outputs.dev_server_pid }}

- name: Archive dev server logs
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: dev-server-logs-${{ env.artifact_suffix }}
path: dev-server-logs.txt
if-no-files-found: ignore

- name: Archive playwright reports
if: ${{ failure() }}
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ env.artifact_suffix }}
path: playwright-report/
if-no-files-found: ignore

# Aggregate all e2e matrix jobs, used in branch protection
e2e-all:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
runs-on: ubuntu-latest
needs: e2e
needs: [ e2e, e2e-playwright ]
steps:
- run: echo e2e ok

Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@ release*.json
arg.bin
args.txt
proposal.md

# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
64 changes: 64 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@dfinity/internet-identity-vite-plugins": "*",
"@eslint/compat": "^1.2.5",
"@eslint/js": "^9.18.0",
"@playwright/test": "^1.52.0",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.20.6",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
Expand Down
63 changes: 63 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { defineConfig, devices } from "@playwright/test";

/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// import path from 'path';
// dotenv.config({ path: path.resolve(__dirname, '.env') });

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./src/frontend/tests/e2e-playwright",
/* 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: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://localhost:3000',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},
timeout: 60000,

/* Configure projects for major browsers */
projects: [
{
name: "desktop",
use: {
...devices["Desktop Chrome"],
launchOptions: {
args: [
"--ignore-certificate-errors",
"--host-resolver-rules=MAP * localhost:5173",
],
},
},
},
{
name: "mobile",
use: {
...devices["Pixel 5"],
launchOptions: {
args: [
"--ignore-certificate-errors",
"--host-resolver-rules=MAP * localhost:5173",
],
},
},
},
],
});
10 changes: 9 additions & 1 deletion src/frontend/src/lib/components/layout/AuthPanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
type Props = HTMLAttributes<HTMLDivElement>;

const { children, class: className, ...props }: Props = $props();

let divRef = $state<HTMLElement>();
</script>

<div
Expand All @@ -20,9 +22,15 @@
{#if !("disableNavigationAnimation" in page.state)}
{#key page.route.id}
<div
bind:this={divRef}
class="col-start-1 row-start-1 flex flex-col max-sm:flex-1"
in:fly={{ x: 200 * (navigating.delta ?? 1), duration: 200, delay: 80 }}
in:fly={{
x: 200 * (navigating.delta ?? 1),
duration: 200,
delay: 80,
}}
out:fly={{ x: -160 * (navigating.delta ?? 1), duration: 160 }}
onoutrostart={() => divRef?.setAttribute("aria-hidden", "true")}
>
{@render children?.()}
</div>
Expand Down
8 changes: 6 additions & 2 deletions src/frontend/src/lib/components/layout/Header.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
onclick={() => (isIdentityPopoverOpen = true)}
variant="tertiary"
class="ml-auto gap-2.5 pr-3 md:-mr-3"
aria-label="Switch identity"
>
<span>{selectedIdentity.name ?? selectedIdentity.identityNumber}</span>
<ChevronDownIcon size="1rem" />
Expand All @@ -65,7 +66,10 @@
lastUsedIdentitiesStore.selectIdentity(identityNumber);
isIdentityPopoverOpen = false;
}}
useAnotherIdentity={() => (isSignInDialogOpen = true)}
useAnotherIdentity={() => {
isIdentityPopoverOpen = false;
isSignInDialogOpen = true;
}}
onClose={() => (isIdentityPopoverOpen = false)}
/>
</Popover>
Expand All @@ -76,13 +80,13 @@
<UseAnotherIdentity
onCancel={() => (isSignInDialogOpen = false)}
onSuccess={(identityNumber) => {
isSignInDialogOpen = false;
lastUsedIdentitiesStore.selectIdentity(identityNumber);
goto("/authorize/account", {
replaceState: true,
invalidateAll: true,
state: { disableNavigationAnimation: true },
});
isSignInDialogOpen = false;
}}
/>
</Dialog>
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/src/lib/components/ui/IdentitySwitcher.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
size="sm"
iconOnly
class="ml-auto !rounded-full"
aria-label="Close"
>
<XIcon size="1.25rem" />
</Button>
Expand All @@ -88,7 +89,7 @@
<div class="text-text-primary font-semibold">
{identity.name ?? identity.identityNumber}
</div>
<div class="text-text-tertiary">
<div class="text-text-tertiary" aria-hidden="true">
{"passkey" in identity.authMethod ? "Passkey" : "Google"}
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/components/views/CreateAccount.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
spellcheck="false"
disabled={loading}
error={name.length > 32 ? "Maximum length is 32 characters." : undefined}
aria-label="Account name"
/>
</div>
<div class="mt-auto flex flex-col items-stretch gap-3">
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/components/views/CreatePasskey.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
spellcheck="false"
disabled={loading}
error={name.length > 64 ? "Maximum length is 64 characters." : undefined}
aria-label="Identity name"
/>
</div>
<div class="mt-auto flex flex-col items-stretch gap-3">
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/lib/flows/dappsExplorer/dapps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { features } from "$lib/legacy/features";
// * Only dapps using II are used
// * All relevant logos are copied to II's assets
// * Some logos are converted to webp
import dappsJson from "./dapps.json";
import dappsJson from "./dapps.json" with { type: "json" };

// This path should point to internet-identity/src/frontend/src/assets/icons/*
const iconFiles = import.meta.glob("$lib/icons/*", {
Expand Down
Loading
Loading