diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cdfc2ce..c94c22d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: key: ${{ runner.os }}-docker-default-${{ github.sha }} restore-keys: | ${{ runner.os }}-docker-default- - - name: Run tests without captcha + - name: Run default tests run: | cd demo docker compose up -d @@ -55,8 +55,33 @@ jobs: cd .. npm run e2e:captcha:ci + tests_passkey: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Prepare + uses: ./.github/actions/prepare + - name: Install demo dependencies + run: npm ci + working-directory: demo + - name: Cache Docker layers for passkey image + uses: actions/cache@v3 + with: + path: /home/runner/.docker + key: ${{ runner.os }}-docker-passkey-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-docker-passkey- + - name: Run tests with passkey + run: | + cd demo + docker compose -f docker-compose.passkey.yml up -d + cd .. + npm run e2e:passkey:ci + may-merge: - needs: ['tests', 'tests_captcha'] + needs: ['tests', 'tests_captcha', 'tests_passkey'] runs-on: ubuntu-latest steps: - name: Cleared for merging diff --git a/README.md b/README.md index 1fb7511..3b9411a 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,16 @@ testWithII('should sign-in with a new user when II requires a captcha', async ({ }); ``` +Similarly, you can test a flow where Internet Identity requires the user to create and save a passkey: + +```javascript +testWithII('should sign in with a new user when II requires a passkey', async ({page, iiPage}) => { + await page.goto('/'); + + await iiPage.signInWithNewIdentity({createPasskey: true}); +}); +``` + ### 3. Wait for Internet Identity (optional) You might encounter scenarios where you perform tests against a local replica started in parallel with your tests, commonly when automating the tests in a CI environment. The library also exposes a fixture that lets you wait for Internet Identity to be ready. @@ -167,6 +177,20 @@ Then, navigate to the root directory and run the dedicated test: npm run e2e:captcha ``` +### Running Required Passkey Tests Locally + +The default test suite validates the use of the latest Internet Identity, which does not require the user to complete a specific step to create a passkey. To test a flow where passkey creation is required, run the following command from the `demo` directory: + +```bash +docker compose -f docker-compose.passkey.yml up +``` + +Then, navigate to the root directory and run the dedicated test: + +```bash +npm run e2e:passkey +``` + ## 🚧 Limitations Currently, the library's fixtures cannot be implemented with Playwright's ability to [load existing authenticated state](https://playwright.dev/docs/auth). Playwright currently does not support IndexedDB for such features. This limitation is tracked in their [GitHub issue #11164](https://github.com/microsoft/playwright/issues/11164). diff --git a/demo/docker-compose.passkey.yml b/demo/docker-compose.passkey.yml new file mode 100644 index 0000000..e0d81c1 --- /dev/null +++ b/demo/docker-compose.passkey.yml @@ -0,0 +1,12 @@ +services: + juno-satellite: + image: junobuild/satellite:0.0.57 + ports: + - 5987:5987 + volumes: + - juno_satellite_passkey:/juno/.juno + - ./juno.dev.config.js:/juno/juno.dev.config.js + - ./target/deploy:/juno/target/deploy/ + +volumes: + juno_satellite_passkey: diff --git a/e2e/captcha.spec.ts b/e2e/captcha.spec.ts index 1b5ef60..b993d92 100644 --- a/e2e/captcha.spec.ts +++ b/e2e/captcha.spec.ts @@ -8,5 +8,5 @@ testWithII.beforeEach(async ({iiPage}) => { testWithII('should sign-in with a new user when II requires a captcha', async ({page, iiPage}) => { await page.goto('/'); - await iiPage.signInWithNewIdentity({captcha: true}); + await iiPage.signInWithNewIdentity({captcha: true, createPasskey: true}); }); diff --git a/e2e/passkey.spec.ts b/e2e/passkey.spec.ts new file mode 100644 index 0000000..13436e2 --- /dev/null +++ b/e2e/passkey.spec.ts @@ -0,0 +1,12 @@ +import {testWithII} from '../src'; +import {DOCKER_CONTAINER} from './spec.constants'; + +testWithII.beforeEach(async ({iiPage}) => { + await iiPage.waitReady(DOCKER_CONTAINER); +}); + +testWithII('should sign-in with a new user when II requires a passkey', async ({page, iiPage}) => { + await page.goto('/'); + + await iiPage.signInWithNewIdentity({createPasskey: true}); +}); diff --git a/package.json b/package.json index 7f4c2b0..81f1c1e 100644 --- a/package.json +++ b/package.json @@ -46,10 +46,12 @@ "build": "tsc --noEmit && node rmdir.mjs && node esbuild.mjs && npm run ts-declaration", "lint": "eslint --max-warnings 0", "dev": "npm --prefix demo run dev", - "e2e": "NODE_ENV=development playwright test --grep-invert 'captcha'", - "e2e:ci": "playwright test --reporter=html --grep-invert 'captcha'", + "e2e": "NODE_ENV=development playwright test e2e/login.spec", + "e2e:ci": "playwright test --reporter=html e2e/login.spec", "e2e:captcha": "NODE_ENV=development playwright test e2e/captcha.spec", - "e2e:captcha:ci": "playwright test --reporter=html e2e/captcha.spec" + "e2e:captcha:ci": "playwright test --reporter=html e2e/captcha.spec", + "e2e:passkey": "NODE_ENV=development playwright test e2e/passkey.spec", + "e2e:passkey:ci": "playwright test --reporter=html e2e/passkey.spec" }, "devDependencies": { "@dfinity/eslint-config-oisy-wallet": "^0.1.10", diff --git a/src/page-objects/InternetIdentityPage.ts b/src/page-objects/InternetIdentityPage.ts index e7f6bab..0dd6a6e 100644 --- a/src/page-objects/InternetIdentityPage.ts +++ b/src/page-objects/InternetIdentityPage.ts @@ -99,11 +99,13 @@ export class InternetIdentityPage { * @param {Object} [params] - The optional arguments for the sign-in method. * @param {string} [params.selector] - The selector for the login button. Defaults to [data-tid=login-button]. * @param {boolean} [params.captcha] - Set to true if the II login flow requires a captcha. + * @param {boolean} [params.createPasskey] - Set to true if the II login flow requires the user to create a passkey. * @returns {Promise} A promise that resolves to the new identity number. */ signInWithNewIdentity = async (params?: { selector?: string; captcha?: boolean; + createPasskey?: boolean; }): Promise => { const iiPagePromise = this.context.waitForEvent('page'); @@ -114,7 +116,10 @@ export class InternetIdentityPage { await expect(iiPage).toHaveTitle('Internet Identity'); await iiPage.locator('#registerButton').click(); - await iiPage.locator('[data-action=construct-identity]').click(); + + if (params?.createPasskey === true) { + await iiPage.locator('[data-action=construct-identity]').click(); + } if (params?.captcha === true) { await iiPage.locator('input#captchaInput').fill('a', {timeout: 10000});