Skip to content
Merged
10 changes: 10 additions & 0 deletions e2e/fixtures/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
47 changes: 42 additions & 5 deletions e2e/page-objects/cli.page.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {assertNonNullish, notEmptyString} from '@dfinity/utils';
import type {PrincipalText} from '@dfinity/zod-schemas';
import {execute, spawn} from '@junobuild/cli-tools';
import {readdirSync, statSync} from 'node:fs';
import {readFile, writeFile} from 'node:fs/promises';
import {statSync} from 'node:fs';
import {readdir, readFile, writeFile} from 'node:fs/promises';
import {join} from 'node:path';
import {TestPage} from './_page';

Expand All @@ -23,7 +23,7 @@ export interface CliPageParams {
}

export class CliPage extends TestPage {
readonly #satelliteId: PrincipalText;
#satelliteId: PrincipalText;

private constructor({satelliteId}: CliPageParams) {
super();
Expand Down Expand Up @@ -55,6 +55,12 @@ export class CliPage extends TestPage {
await writeFile(JUNO_CONFIG, content, 'utf-8');
}

async toggleSatelliteId({satelliteId}: {satelliteId: PrincipalText}): Promise<void> {
await this.revertConfig();
this.#satelliteId = satelliteId;
await this.initConfig();
}

protected async loginWithEmulator(): Promise<void> {
await execute({
command: JUNO_CMD,
Expand Down Expand Up @@ -83,6 +89,13 @@ export class CliPage extends TestPage {
});
}

async deployHosting({clear}: {clear: boolean}): Promise<void> {
await execute({
command: JUNO_CMD,
args: buildArgs(['hosting', 'deploy', ...(clear ? ['--clear'] : [])])
});
}

async createSnapshot({
target
}: {
Expand Down Expand Up @@ -126,9 +139,16 @@ export class CliPage extends TestPage {
args: buildArgs(['snapshot', 'download', '--target', target])
});

// Retrieve where the snapshot was created
return await this.getSnapshotFsFolder();
}

// Retrieve where the snapshot was created
async getSnapshotFsFolder(): Promise<{snapshotFolder: string}> {
const snapshotsFolder = join(process.cwd(), '.snapshots');
const [snapshotFolder] = readdirSync(snapshotsFolder, {withFileTypes: true})

const folders = await readdir(snapshotsFolder, {withFileTypes: true});

const [snapshotFolder] = folders
.filter((d) => d.isDirectory())
.map(({name}) => {
const path = join(snapshotsFolder, name);
Expand Down Expand Up @@ -173,6 +193,23 @@ export class CliPage extends TestPage {
return {snapshotId: notEmptyString(snapshotId) ? snapshotId.trim() : undefined};
}

async whoami(): Promise<{accessKey: string}> {
let output = '';

await spawn({
command: JUNO_CMD,
args: buildArgs(['whoami']),
stdout: (o) => (output += o),
silentErrors: true
});

const [_, __, ___, text] = output.split(' ');
const [value] = text.split('\n');
const accessKey = value.replace('\x1B[32m', '').replace('\x1B[39m', '');

return {accessKey: accessKey.trim()};
}

/**
* @override
*/
Expand Down
60 changes: 54 additions & 6 deletions e2e/page-objects/console.page.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {InternetIdentityPage} from '@dfinity/internet-identity-playwright';
import {notEmptyString} from '@dfinity/utils';
import {PrincipalTextSchema} from '@dfinity/zod-schemas';
import {PrincipalText, PrincipalTextSchema} from '@dfinity/zod-schemas';
import {expect} from '@playwright/test';
import {testIds} from '../constants/test-ids.constants';
import {IdentityPage, type IdentityPageParams} from './identity.page';
Expand Down Expand Up @@ -31,8 +31,8 @@ export class ConsolePage extends IdentityPage {
return consolePage;
}

async goto(): Promise<void> {
await this.page.goto('/');
async goto({path}: {path: string} = {path: '/'}): Promise<void> {
await this.page.goto(path);
}

async signIn(): Promise<void> {
Expand All @@ -49,11 +49,15 @@ export class ConsolePage extends IdentityPage {
}

async createSatellite({kind}: {kind: 'website' | 'application'}): Promise<void> {
await expect(this.page.getByTestId(testIds.createSatellite.launch)).toBeVisible();
await expect(this.page.getByTestId(testIds.createSatellite.launch)).toBeVisible({
timeout: 20000
});

await this.page.getByTestId(testIds.createSatellite.launch).click();

await expect(this.page.getByTestId(testIds.createSatellite.create)).toBeVisible();
await expect(this.page.getByTestId(testIds.createSatellite.create)).toBeVisible({
timeout: 15000
});

await this.page.getByTestId(testIds.createSatellite.input).fill('Test');
await this.page.getByTestId(testIds.createSatellite[kind]).click();
Expand All @@ -70,7 +74,9 @@ export class ConsolePage extends IdentityPage {
async visitSatelliteSite(
{title}: {title: string} = {title: 'Juno / Satellite'}
): Promise<SatellitePage> {
await expect(this.page.getByTestId(testIds.satelliteOverview.visit)).toBeVisible();
await expect(this.page.getByTestId(testIds.satelliteOverview.visit)).toBeVisible({
timeout: 20000
});

const satellitePagePromise = this.context.waitForEvent('page');

Expand All @@ -87,6 +93,18 @@ export class ConsolePage extends IdentityPage {
});
}

async getICP(): Promise<void> {
await expect(this.page.getByTestId(testIds.navbar.openWallet)).toBeVisible();

await this.page.getByTestId(testIds.navbar.openWallet).click();

await expect(this.page.getByTestId(testIds.navbar.getIcp)).toBeVisible();

await this.page.getByTestId(testIds.navbar.getIcp).click();

await expect(this.page.getByText('55.0001')).toBeVisible({timeout: 65000});
}

async copySatelliteID(): Promise<string> {
await expect(this.page.getByTestId(testIds.satelliteOverview.copySatelliteId)).toBeVisible();

Expand All @@ -99,4 +117,34 @@ export class ConsolePage extends IdentityPage {

return satelliteId;
}

async addSatelliteAdminAccessKey({
satelliteId,
accessKey
}: {
satelliteId: PrincipalText;
accessKey: string;
}): Promise<void> {
await this.goto({path: `/satellite/?s=${satelliteId}&tab=setup`});

const btnLocator = this.page.locator('button', {hasText: 'Add an access key'});
await expect(btnLocator).toBeVisible({timeout: 10000});
await btnLocator.click();

const form = this.page.locator('form');

await form.getByRole('radio', {name: /enter one manually/i}).check();

const keyField = form.getByLabel('Access Key ID');
await expect(keyField).toBeEnabled();
await keyField.fill(accessKey);

await form.locator('select[name="scope"]').selectOption('admin');

const submitLocator = form.getByRole('button', {name: /^submit$/i});
await expect(submitLocator).toBeEnabled();
await submitLocator.click();

await expect(this.page.getByText('Access Key Added')).toBeVisible({timeout: 10000});
}
}
43 changes: 42 additions & 1 deletion e2e/snapshots.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ testWithII('should create and restore a snapshot', async () => {
});

testWithII('should create, download, delete, upload and restore a snapshot', async () => {
testWithII.slow();
testWithII.setTimeout(120_000);

const {consolePage, cliPage} = getTestPages();

Expand All @@ -52,3 +52,44 @@ testWithII('should create, download, delete, upload and restore a snapshot', asy
await satellitePage.reload();
await satellitePage.assertScreenshot();
});

testWithII(
'should create, download, delete, upload and restore a snapshot to another satellite',
async () => {
testWithII.setTimeout(120_000);

const {consolePage, cliPage} = getTestPages();

await consolePage.getICP();

await consolePage.goto();

await consolePage.createSatellite({kind: 'application'});

const satelliteId = await consolePage.copySatelliteID();

await cliPage.toggleSatelliteId({satelliteId});

const {accessKey} = await cliPage.whoami();

await consolePage.addSatelliteAdminAccessKey({accessKey, satelliteId});

await cliPage.deployHosting({clear: true});

await consolePage.goto({path: `/satellite/?s=${satelliteId}`});

const satellitePage = await consolePage.visitSatelliteSite({
title: 'Hello World'
});
await satellitePage.assertScreenshot();

const {snapshotFolder} = await cliPage.getSnapshotFsFolder();

await cliPage.uploadSnapshot({...SNAPSHOT_TARGET, folder: snapshotFolder});

await cliPage.restoreSnapshot(SNAPSHOT_TARGET);

await satellitePage.reload();
await satellitePage.assertScreenshot();
}
);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions juno.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ export default defineConfig({
development: '<DEV_SATELLITE_ID>',
production: '<PROD_SATELLITE_ID>'
},
source: 'build',
predeploy: ['npm run build'],
source: 'e2e/fixtures',
precompress: false,
collections: {
datastore: [
{
Expand Down