diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 578674a77..426e85d9b 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -38,7 +38,7 @@ jobs: strategy: matrix: - node_version: [16, 18] + test_target: [api, ui] runs-on: ubuntu-latest @@ -55,7 +55,7 @@ jobs: - name: Setup Node and pnpm uses: silverhand-io/actions-node-pnpm-run-steps@v2 with: - node-version: ${{ matrix.node_version }} + node-version: 18 run-install: false # Setup integration test @@ -99,6 +99,7 @@ jobs: - name: Run tests run: | cd tests/packages/integration-tests - pnpm start + pnpm build + pnpm test:${{ matrix.test_target }} env: INTEGRATION_TESTS_LOGTO_URL: http://localhost:3001 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index abca19613..882cdb0c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,17 +49,13 @@ jobs: main-test: runs-on: ubuntu-latest - strategy: - matrix: - node_version: [16, 18] - steps: - uses: actions/checkout@v3 - name: Setup Node and pnpm uses: silverhand-io/actions-node-pnpm-run-steps@v2 with: - node-version: ${{ matrix.node_version }} + node-version: 18 - name: Build for test run: pnpm -r build:test diff --git a/packages/integration-tests/jest.config.ui.js b/packages/integration-tests/jest.config.ui.js index dddbf5004..2e58afa04 100644 --- a/packages/integration-tests/jest.config.ui.js +++ b/packages/integration-tests/jest.config.ui.js @@ -1,6 +1,7 @@ /** @type {import('jest').Config} */ const config = { preset: 'jest-puppeteer', + setupFilesAfterEnv: ['./jest.setup.js'], moduleNameMapper: { '^#src/(.*)\\.js(x)?$': '/lib/$1', '^(chalk|inquirer)$': '/../shared/lib/esm/module-proxy.js', diff --git a/packages/integration-tests/src/tests/api/session.test.ts b/packages/integration-tests/src/tests/api/session.test.ts index b7cf82824..5b05446ba 100644 --- a/packages/integration-tests/src/tests/api/session.test.ts +++ b/packages/integration-tests/src/tests/api/session.test.ts @@ -38,9 +38,6 @@ import { generateUsername, generatePassword, generateEmail, generatePhone } from const connectorIdMap = new Map(); describe('username and password flow', () => { - const username = generateUsername(); - const password = generatePassword(); - beforeAll(async () => { await setSignUpIdentifier(signUpIdentifiers.username, true); await setSignInMethod([ @@ -54,6 +51,8 @@ describe('username and password flow', () => { }); it('register and sign in with username & password', async () => { + const username = generateUsername(); + const password = generatePassword(); await expect(registerNewUser(username, password)).resolves.not.toThrow(); await expect(signIn({ username, password })).resolves.not.toThrow(); }); diff --git a/packages/integration-tests/src/tests/ui/smoke.test.ts b/packages/integration-tests/src/tests/ui/smoke.test.ts index 9aa405bb8..85221cd66 100644 --- a/packages/integration-tests/src/tests/ui/smoke.test.ts +++ b/packages/integration-tests/src/tests/ui/smoke.test.ts @@ -1,8 +1,74 @@ import { logtoUrl } from '#src/constants.js'; +import { generatePassword } from '#src/utils.js'; describe('smoke testing', () => { - it('opens with app element', async () => { - await page.goto(new URL('/sign-in', logtoUrl).href); - await expect(page.$('#app')).resolves.not.toBeNull(); + const consoleUsername = 'admin'; + const consolePassword = generatePassword(); + + it('opens with app element and navigates to sign-in page', async () => { + await page.goto(logtoUrl); + await page.waitForNavigation({ waitUntil: 'networkidle0' }); + + await expect(page.waitForSelector('#app')).resolves.not.toBeNull(); + expect(page.url()).toBe(new URL('console/welcome', logtoUrl).href); + }); + + it('registers a new admin account and automatically signs in', async () => { + const createAccountButton = await page.waitForSelector('button'); + expect(createAccountButton).not.toBeNull(); + await createAccountButton.click(); + await page.waitForNavigation({ waitUntil: 'networkidle0' }); + expect(page.url()).toBe(new URL('register', logtoUrl).href); + + const usernameField = await page.waitForSelector('input[name=new-username]'); + const submitButton = await page.waitForSelector('button'); + + await usernameField.type(consoleUsername); + await submitButton.click(); + await page.waitForNavigation({ waitUntil: 'networkidle0' }); + expect(page.url()).toBe(new URL('register/username/password', logtoUrl).href); + + const passwordField = await page.waitForSelector('input[name=new-password]'); + const confirmPasswordField = await page.waitForSelector('input[name=confirm-new-password]'); + const saveButton = await page.waitForSelector('button'); + await passwordField.type(consolePassword); + await confirmPasswordField.type(consolePassword); + await saveButton.click(); + await page.waitForNavigation({ waitUntil: 'networkidle0' }); + + expect(page.url()).toBe(new URL('console/get-started', logtoUrl).href); + }); + + it('signs out of admin console', async () => { + const userElement = await page.waitForSelector('div[class$=topbar] > div[class$=container]'); + await userElement.click(); + const signOutButton = await page.waitForSelector('.ReactModalPortal ul li'); + await signOutButton.click(); + + await page.waitForNavigation({ waitUntil: 'networkidle0' }); + expect(page.url()).toBe(new URL('sign-in', logtoUrl).href); + }); + + it('signs in to admin console', async () => { + const usernameField = await page.waitForSelector('input[name=username]'); + const passwordField = await page.waitForSelector('input[name=password]'); + const submitButton = await page.waitForSelector('button'); + + await usernameField.type(consoleUsername); + await passwordField.type(consolePassword); + await submitButton.click(); + + await page.waitForNavigation({ waitUntil: 'networkidle0' }); + expect(page.url()).toBe(new URL('console/get-started', logtoUrl).href); + + const userElement = await page.waitForSelector('div[class$=topbar] > div:last-child'); + const usernameString = await userElement.$eval('div > div', (element) => element.textContent); + expect(usernameString).toBe(consoleUsername); + }); + + it('renders SVG correctly with viewbox property', async () => { + const logoSvg = await page.waitForSelector('div[class$=topbar] > svg[viewbox]'); + + expect(logoSvg).not.toBeNull(); }); });