Skip to content
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

Move online smoke test to playwright #4567

Merged
merged 2 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 1 addition & 3 deletions .github/workflows/build-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -635,8 +635,6 @@ jobs:
k8s-distribution: ${{ matrix.cluster.distribution }}
k8s-version: ${{ matrix.cluster.version }}
k8s-instance-type: ${{ matrix.cluster.instance_type }}
testim-access-token: '${{ secrets.TESTIM_ACCESS_TOKEN }}'
testim-branch: ${{ github.head_ref == 'main' && 'master' || github.head_ref }}
aws-access-key-id: '${{ secrets.E2E_SUPPORT_BUNDLE_AWS_ACCESS_KEY_ID }}'
aws-secret-access-key: '${{ secrets.E2E_SUPPORT_BUNDLE_AWS_SECRET_ACCESS_KEY }}'
replicated-api-token: '${{ secrets.C11Y_MATRIX_TOKEN }}'
Expand Down Expand Up @@ -4125,7 +4123,6 @@ jobs:
- ci-test-kots
# testim tests
- validate-existing-online-install-minimal
- validate-smoke-test
- validate-version-history-pagination
- validate-change-license
- validate-min-kots-version
Expand All @@ -4137,6 +4134,7 @@ jobs:
- validate-support-bundle
- validate-gitops
# playwright tests
- validate-smoke-test
- validate-backup-and-restore
- validate-no-required-config
- validate-config
Expand Down
3 changes: 2 additions & 1 deletion e2e/inventory/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ func NewRegressionTest() Test {

func NewSmokeTest() Test {
return Test{
ID: "smoke-test",
Name: "Smoke Test",
TestimSuite: "smoke-test",
Namespace: "smoke-test",
AppSlug: "qakotstestim",
UpstreamURI: "qakotstestim/github-actions-qa",
NeedsSnapshots: true,
}
Expand Down
3 changes: 2 additions & 1 deletion e2e/playwright/tests/shared/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './login';
export * from './upload-license';
export * from './upload-license';
export * from './validate-deploy-logs';
12 changes: 12 additions & 0 deletions e2e/playwright/tests/shared/validate-deploy-logs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const validateDeployLogs = async (page, expect) => {
await expect(page.getByText('dryrunStdout')).toBeVisible();
await expect(page.getByText('dryrunStderr')).toBeVisible();
await expect(page.getByText('applyStdout')).toBeVisible();
await expect(page.getByText('applyStderr')).toBeVisible();
await expect(page.getByText('helmStdout')).toBeVisible();
await expect(page.getByText('helmStderr')).toBeVisible();
await page.getByText('dryrunStderr').click();
await page.getByText('applyStdout').click();
await expect(page.locator('.view-lines')).toContainText('created');
await page.getByRole('button', { name: 'Ok, got it!' }).click();
};
23 changes: 23 additions & 0 deletions e2e/playwright/tests/smoke-test/license.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: kots.io/v1beta1
kind: License
metadata:
name: githubactionqa
spec:
appSlug: qakotstestim
channelID: 1qcbLyQFdfxq28RbSN4wEtqaxcZ
channelName: Github Actions QA
customerName: GitHub Action QA
endpoint: https://replicated.app
entitlements:
expires_at:
description: License Expiration
title: Expiration
value: ""
valueType: String
isAirgapSupported: true
isGitOpsSupported: true
isSnapshotSupported: true
licenseID: 1qcbXQRwHNCbYIchxIDwuLdLkVa
licenseSequence: 1
licenseType: prod
signature: eyJsaWNlbnNlRGF0YSI6ImV5SmhjR2xXWlhKemFXOXVJam9pYTI5MGN5NXBieTkyTVdKbGRHRXhJaXdpYTJsdVpDSTZJa3hwWTJWdWMyVWlMQ0p0WlhSaFpHRjBZU0k2ZXlKdVlXMWxJam9pWjJsMGFIVmlZV04wYVc5dWNXRWlmU3dpYzNCbFl5STZleUpzYVdObGJuTmxTVVFpT2lJeGNXTmlXRkZTZDBoT1EySlpTV05vZUVsRWQzVk1aRXhyVm1FaUxDSnNhV05sYm5ObFZIbHdaU0k2SW5CeWIyUWlMQ0pqZFhOMGIyMWxjazVoYldVaU9pSkhhWFJJZFdJZ1FXTjBhVzl1SUZGQklpd2lZWEJ3VTJ4MVp5STZJbkZoYTI5MGMzUmxjM1JwYlNJc0ltTm9ZVzV1Wld4SlJDSTZJakZ4WTJKTWVWRkdaR1o0Y1RJNFVtSlRUalIzUlhSeFlYaGpXaUlzSW1Ob1lXNXVaV3hPWVcxbElqb2lSMmwwYUhWaUlFRmpkR2x2Ym5NZ1VVRWlMQ0pzYVdObGJuTmxVMlZ4ZFdWdVkyVWlPakVzSW1WdVpIQnZhVzUwSWpvaWFIUjBjSE02THk5eVpYQnNhV05oZEdWa0xtRndjQ0lzSW1WdWRHbDBiR1Z0Wlc1MGN5STZleUpsZUhCcGNtVnpYMkYwSWpwN0luUnBkR3hsSWpvaVJYaHdhWEpoZEdsdmJpSXNJbVJsYzJOeWFYQjBhVzl1SWpvaVRHbGpaVzV6WlNCRmVIQnBjbUYwYVc5dUlpd2lkbUZzZFdVaU9pSWlMQ0oyWVd4MVpWUjVjR1VpT2lKVGRISnBibWNpZlgwc0ltbHpRV2x5WjJGd1UzVndjRzl5ZEdWa0lqcDBjblZsTENKcGMwZHBkRTl3YzFOMWNIQnZjblJsWkNJNmRISjFaU3dpYVhOVGJtRndjMmh2ZEZOMWNIQnZjblJsWkNJNmRISjFaWDE5IiwiaW5uZXJTaWduYXR1cmUiOiJleUpzYVdObGJuTmxVMmxuYm1GMGRYSmxJam9pV2tKVWMyMWxRVW81YW5Vd01EVmlSbkpGVDNWMlpYRkNkMmt5UjNjeE5rSXhNRXR6VWtSb1JqRm9kMVYwVTNSTWVWRkhUR2g2Ym5OWFVIRndVR1JYTmxsSFZrOVBOWFpDVlU1RGJIZHpURTlETDIxRUt6TnhOWEJNVGxkdVF6SmplbTVGTDA0eE1EVnJWSFJYVDNGa1RXdzFTa3B3T1dwbFNETkhNbm93Y21kelFXOVRZVWd6Y20xMmNYZERhekpGTldabmExZE1Sa0U0TDBGbVNYZEZRbU5FY1dOdFpEWnViVFJFYkZoQlJVcE9hRlJUYjFWNVpTdEpXR2xKTlZGWFZuTmlhR2ROWml0bVYyeG1lV2hRYkVsMmNDODVjVUYyTDI1blFUTkhSVmh0UVZOeU1XSXlhVkZpU25SaVpGQlVkM1JDVFdoalJscDRabE53WlZaRk4xWk9MelJ4VG1GdE1ubGpOMEpEZW1GcGNtdG1PRzlETUZkc1JtaHpWVFkzSzB0ck9HRmxRM0pKVEZCR1ZWcHVjVFF5ZUdaMVZ6UXZWekJXU21VemVrVkRjSGx4YmtkMlptNDNPRlZVYTJoblRuVXlWemRuUFQwaUxDSndkV0pzYVdOTFpYa2lPaUl0TFMwdExVSkZSMGxPSUZCVlFreEpReUJMUlZrdExTMHRMVnh1VFVsSlFrbHFRVTVDWjJ0eGFHdHBSemwzTUVKQlVVVkdRVUZQUTBGUk9FRk5TVWxDUTJkTFEwRlJSVUYyWVRFNVRFUlFWQ3R6VTJaeE5XMU9iemw2YzF4dVNIRk5LMGhSSzFoclEyTk5WRTFaTUZGR1lTdDNRa1p6WWtwdFVFTjVheXRqTTNORmRUTTFSMDVZUTBsamVqWlFUbk0yZGtOdWFuQmhNVFJwZGpOMVdseHVSRmxzY0hCU2QyZzFPSEJ5UldoYVZrOUhXVmxhYm5KeVZIWXllV3Q2VUhWMFNuZFdUazFhUWpSQ1RsTjRWalZFYURCd1dFZ3hWaXRxV1V0VmJFRlJhMXh1Y25aUVZVRk5ObmsxUTBscmVGUjBOM3B1U0U5eVMwWlJRMVJGZWxOS1lsUllUalJPYjNkdVdscFJZVFY2ZWxsWldsTTRkV0pHVFVaNEswVlRVbk5wYjF4dWJWUXZWMEpEUzA1RlIzbEpOMlY0WkdoTlZHMXFNRFUyVkZoUmFHaG1VVk01WkZVclpYTk5NelprSzJsSVRHTkRaeTlyWmtaNVlTdFRiM1puVlVJdmJGeHVZVWhCU0ZKM2RrTkJLMjVzTkRKelpFSlZkRXBIU21VcmRpOUtPVVYxY2tod01pdFNRMnM0Ylc1aFVYUkdNVTh5TmpKeFExUXhaQ3R5Tm5oTWEzcHpORnh1WTFGSlJFRlJRVUpjYmkwdExTMHRSVTVFSUZCVlFreEpReUJMUlZrdExTMHRMVnh1SWl3aWEyVjVVMmxuYm1GMGRYSmxJam9pWlhsS2VtRlhaSFZaV0ZJeFkyMVZhVTlwU25sTk0yUkhWbXR3YzFReFdqQmpNSGcwV1d4R1NsRnFTbEpNTUZKdVRUSkdSVlZVYUhSamJFcE5Za2hvY1dWRlZtMWpXR1JJWkdwYWNWa3dkR0ZPVkdoaFZHcFNWRmRyZUVOVFNFSkpaRlJaY21ReVJuaGliWEF4VGpKS1dXSnFaSFpQV0ZVeVVrZFNhVkV3TVcxWmJrNWFXV3h3UTJKR1ZuZFdSRlpUVjBkdk0xa3lXakpWVms1RFkwaE9ZVk5zU2pCa1dIQlJZMWh3UjFwc1FtMWliVmt3VkRGSmNtTkhPVk5sYld4RlRsaHdTV0ZwT1Vsa1ZYUk9XVEprZVZsVVRrZGxWWE15WW5wU2JGTnNSbWxaYTFKWFpHMXNTVkpUZEhSYWEwa3hZMjFXYmxSR1RqRldSVTUxVjJ0amVGWnVTa1ZPYTJocVZEQmFhMlZFVGpOU1IxcEdZbFJvZWxOV1dsZE9XRmt5VlVoVk5WRnJhRVJPZW1nd1VqRk9SRTFFU1ROUlZtUmFWR3RrZWxkRlZqTmtNMmN5VVZkMFZGTXdXbXROTVhCRFRVWnZkMkY1ZEd4Wk0yczFUMWRPVUUxc1NuUlVTRkpGVFcwNVEwNHdSak5PYlhBeVRVVktOVmxWUmxST2JYUnlTekZrU0Zvd09XaFhhbGwzVjBOMFdGSnVXbWxOUkVweFZGZFpNMk50ZEV4VlZYaDZXbXhDTlZaVVpGQmhSWGN6VVcxS1JWZEdSazVrUkVwYVdXMTRNMUpZY0UxVmF6bHFWMnhhTm1GWVdrOWxiRnBPVXpKbmNsWnRZemxRVTBselNXMWtjMkl5U21oaVJYUnNaVlZzYTBscWIybFpiVkpzV2xSVk1rNVVXWGRaTWxwcFRrUk9hazlYU1hsUFIwcHRUMVJvYkZsWFRtaGFiVVV5VGtSWmFXWlJQVDBpZlE9PSJ9
195 changes: 195 additions & 0 deletions e2e/playwright/tests/smoke-test/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import { test, expect } from '@playwright/test';
import { login, uploadLicense, validateDeployLogs } from '../shared';

const { execSync } = require("child_process");

test('smoke test', async ({ page }) => {
test.setTimeout(5 * 60 * 1000); // 5 minutes
await login(page);
await uploadLicense(page, expect);
await expect(page.locator('#app')).toContainText('Install in airgapped environment', { timeout: 15000 });
await page.getByText('download App Name from the Internet').click();
await expect(page.locator('#app')).toContainText('Installing your license');
await expect(page.locator('h3')).toContainText('My Example Config', { timeout: 30000 });
await page.locator('#a_bool-group').getByText('a bool field').click();
await page.locator('#a_required_text-group').getByRole('textbox').click();
await page.locator('#a_required_text-group').getByRole('textbox').fill('my required text field');
await expect(page.locator('#version_sequence-group')).toContainText('This version is 0');
await page.getByRole('button', { name: 'Continue' }).click();
await expect(page.locator('#app')).toContainText('Results', { timeout: 30000 });
await expect(page.locator('#app')).toContainText('Sequence is 0');
await page.getByRole('button', { name: 'Deploy' }).click();
await page.getByRole('button', { name: 'Deploy anyway' }).click();
await expect(page.locator('#app')).toContainText('Ready', { timeout: 30000 });
await expect(page.locator('#app')).toContainText('Currently deployed version', { timeout: 15000 });
await expect(page.locator('#app')).toContainText('Check for update');
await expect(page.locator('#app')).toContainText('Configure automatic updates');
await expect(page.locator('#app')).toContainText('Redeploy', { timeout: 15000 });
await page.getByRole('link', { name: 'Version history' }).click();
await expect(page.locator('.currentVersion--wrapper')).toContainText('Sequence 0');
await expect(page.locator('#app')).toContainText('Currently deployed version');
await expect(page.locator('#app')).toContainText('Check for update');
await expect(page.locator('#app')).toContainText('Configure automatic updates');
await expect(page.getByRole('button')).toContainText('Redeploy');
await page.getByText('Configure automatic updates').click();
await expect(page.locator('.ConfigureUpdatesModal')).toContainText('Default');
await expect(page.locator('.ConfigureUpdatesModal')).toContainText('Every 4 hours');
await expect(page.locator('label')).toContainText('Enable automatic deployment');
await page.locator('.replicated-select__control').click();
await page.locator('.replicated-select__option').getByText('Weekly', { exact: true }).click();
await expect(page.locator('.ConfigureUpdatesModal')).toContainText('Weekly');
await expect(page.locator('.ConfigureUpdatesModal')).toContainText('At 12:00 AM, only on Sunday');
await page.getByRole('button', { name: 'Update', exact: true }).click();
await expect(page.getByText('Automatically check for updates', { exact: true })).not.toBeVisible();
await page.locator('span[data-tip="View deploy logs"]').first().click();
await validateDeployLogs(page, expect);
await page.reload();
await page.getByRole('link', { name: 'Dashboard' }).click();
await expect(page.getByText('App Name')).toBeVisible();
await expect(page.locator('.Dashboard--appIcon')).toBeVisible();
await expect(page.locator('p').filter({ hasText: 'License' })).toBeVisible();
await page.getByText('Configure automatic updates').click();
await expect(page.locator('.ConfigureUpdatesModal')).toContainText('Weekly');
await expect(page.locator('.ConfigureUpdatesModal')).toContainText('At 12:00 AM, only on Sunday');
await expect(page.locator('label')).toContainText('Enable automatic deployment');
await page.getByRole('button', { name: 'Cancel' }).click();
await page.locator('svg.icons.clickable[data-tip="View release notes"]').click();
await expect(page.getByLabel('Release Notes').getByRole('paragraph')).toContainText('release notes - updates');
await page.getByRole('button', { name: 'Close' }).click();
await page.locator('span[data-tip="View deploy logs"]').click();
await validateDeployLogs(page, expect);
await page.getByRole('link', { name: 'Config', exact: true }).click();
await expect(page.locator('h3')).toContainText('My Example Config');
await expect(page.locator('#version_sequence-group')).toContainText('This version is 1');
await expect(page.getByRole('button', { name: 'Save config' })).toBeVisible();
await page.getByRole('link', { name: 'Troubleshoot' }).click();
await expect(page.getByRole('button', { name: 'Analyze App Name' })).toBeVisible();
await page.getByRole('link', { name: 'License' }).click();
await expect(page.locator('#app')).toContainText('Airgap enabled');
await expect(page.locator('#app')).toContainText('Snapshots enabled');
await expect(page.getByRole('button', { name: 'Sync license' })).toBeVisible();
await page.getByRole('link', { name: 'View files' }).click();
await page.getByText('upstream', { exact: true }).click();
await page.getByRole('listitem', { name: 'config.yaml' }).locator('div').click();
await expect(page.locator('.view-lines')).toContainText('apiVersion');
await page.getByText('Click here', { exact: true }).click();
await expect(page.getByRole('heading')).toContainText('Edit patches for your kots application');
await expect(page.getByText('Copy command').first()).toBeVisible();

let downloadCommand = await page.locator('.react-prism.language-bash').first().textContent();
if (!downloadCommand!.includes('download')) {
throw new Error("Expected the download command to contain the word 'download'");
}
downloadCommand = `${downloadCommand} --overwrite`;
console.log(downloadCommand, "\n");
execSync(downloadCommand, {stdio: 'inherit'});

await expect(page.getByText('Copy command').last()).toBeVisible();
let uploadCommand = await page.locator('.react-prism.language-bash').last().textContent();
if (!uploadCommand!.includes('upload')) {
throw new Error("Expected the upload command to contain the word 'upload'");
}
console.log(uploadCommand, "\n");
execSync(uploadCommand, {stdio: 'inherit'});

await page.getByRole('button', { name: 'Ok, got it!' }).click();
await page.getByRole('link', { name: 'Version history' }).click();
await expect(page.locator('#app')).toContainText('KOTS Upload');
await expect(page.getByText('Running checks', { exact: true }).first()).not.toBeVisible({ timeout: 30000 });
await page.getByRole('button', { name: 'Deploy' }).first().click();
await page.getByRole('button', { name: 'Deploy this version' }).click();
await expect(page.locator('#app')).toContainText('Deploying');
await expect(page.locator('#app')).toContainText('Currently deployed version');
await expect(page.locator('#app')).toContainText('Application up to date.');
await expect(page.locator('.currentVersion--wrapper')).toContainText('Sequence 1');
await page.getByRole('link', { name: 'Registry settings' }).click();
await page.getByPlaceholder('artifactory.some-big-bank.com').click();
await page.getByPlaceholder('artifactory.some-big-bank.com').fill('ttl.sh');
await page.getByPlaceholder('username').click();
await page.getByPlaceholder('username').fill('admin');
await page.getByPlaceholder('password').click();
await page.getByPlaceholder('password').fill('admin');
await page.getByRole('button', { name: 'Test connection' }).click();
await expect(page.locator('form')).toContainText('Success!');
await page.getByRole('button', { name: 'Save changes' }).click();
await expect(page.getByRole('button', { name: 'Save changes' })).toBeDisabled();
await expect(page.locator('.Loader')).toBeVisible();
await expect(page.locator('#app')).toContainText('Writing manifest to image destination', { timeout: 30000 });
await expect(page.getByRole('button', { name: 'Save changes' })).toBeEnabled({ timeout: 30000 });
await expect(page.locator('.Loader')).not.toBeVisible();
await page.getByRole('link', { name: 'Version history' }).click();
await expect(page.locator('#app')).toContainText('Registry Change');
await expect(page.locator('#app')).toContainText('Sequence 2');
await page.getByRole('link', { name: 'Registry settings' }).click();
await page.getByRole('button', { name: 'Stop using registry' }).click();
await page.getByRole('button', { name: 'OK' }).click();
await expect(page.locator('.Loader')).toBeVisible();
await expect(page.getByRole('button', { name: 'Stop using registry' })).toBeDisabled();
await expect(page.getByRole('button', { name: 'Save changes' })).toBeEnabled({ timeout: 30000 });
await expect(page.locator('.Loader')).not.toBeVisible();
await expect(page.getByPlaceholder('artifactory.some-big-bank.com')).toBeEmpty();
await expect(page.getByPlaceholder('username')).toBeEmpty();
await expect(page.getByPlaceholder('password')).toBeEmpty();
await expect(page.getByPlaceholder('namespace')).toBeEmpty();
await page.waitForTimeout(2000);
await page.getByRole('link', { name: 'Version history' }).click();
await expect(page.locator('#app')).toContainText('Sequence 3', { timeout: 10000 });
await expect(page.locator('#app')).toContainText('Registry Change');
await expect(page.locator('.NavItem').getByText('Application', { exact: true })).toBeVisible();
await expect(page.locator('.NavItem').getByText('GitOps', { exact: true })).toBeVisible();
await expect(page.locator('.NavItem').getByText('Snapshots', { exact: true })).toBeVisible();
await expect(page.locator('div').filter({ hasText: /^Change passwordAdd new applicationLog out$/ }).getByRole('img')).toBeVisible();
await page.locator('.NavItem').getByText('Snapshots', { exact: true }).click();
await page.getByRole('link', { name: 'Settings & Schedule' }).click();
await expect(page.locator('#app')).toContainText('Snapshot settings');
await page.getByText('+ Add a new destination').click();
await expect(page.getByRole('button', { name: 'Check for Velero' })).toBeVisible();
await page.getByRole('button', { name: 'Check for Velero' }).click();
await expect(page.getByLabel('Modal')).toContainText('Velero is installed on your cluster');
await page.getByRole('button', { name: 'Ok, got it!' }).click();
await page.getByRole('link', { name: 'Full Snapshots (Instance)' }).click();
await expect(page.locator('#app')).toContainText('No snapshots yet');
await page.getByRole('button', { name: 'Start a snapshot' }).click();
await expect(page.locator('#app')).toContainText('In Progress');
await expect(page.locator('#app')).toContainText('Completed', { timeout: 300000 });
await page.getByText('Learn more').click();
await page.getByRole('button', { name: 'Ok, got it!' }).click();
await expect(page.locator('#app')).toContainText('Full Snapshots (Instance)');
await page.getByRole('link', { name: 'Partial Snapshots (Application)' }).click();
await page.getByRole('button', { name: 'Start a snapshot' }).click();
await expect(page.locator('#app')).toContainText('In Progress');
await expect(page.locator('#app')).toContainText('Completed', { timeout: 30000 });
await expect(page.getByText('It’s recommend that you use')).toBeVisible();
await page.getByText('Learn more').click();
await page.getByRole('button', { name: 'Ok, got it!' }).click();
await expect(page.locator('#app')).toContainText('Partial snapshots (Application)');
await page.getByRole('link', { name: 'Full Snapshots (Instance)', exact: true }).click();
await page.locator('.SnapshotRow--wrapper').click();
await expect(page.locator('#app')).toContainText('Snapshot timeline');
await page.getByText('View logs').click();
await expect(page.locator('.view-lines')).toContainText('level=info');
await page.getByRole('button', { name: 'Ok, got it!' }).click();
await page.getByRole('link', { name: 'Full Snapshots (Instance)', exact: true }).click();
await page.locator('svg.icons.clickable[data-tip="Restore from this backup"]').click();
await expect(page.getByLabel('Modal')).toContainText('Restore from backup');
await expect(page.getByLabel('Modal')).toContainText('Admin console & application');
await expect(page.getByLabel('Modal')).toContainText('Application & metadata only');
await expect(page.getByLabel('Modal')).toContainText('Only restores the admin console');
await page.getByText('Application & metadata only', { exact: true }).click();
await page.getByRole('button', { name: 'Cancel' }).click();
await page.locator('svg.icons.clickable').last().click();
await expect(page.getByLabel('Modal')).toContainText('Delete snapshot');
await page.getByRole('button', { name: 'Delete snapshot' }).click();
await expect(page.locator('#app')).toContainText('Deleting');
await expect(page.locator('#app')).toContainText('No snapshots yet', { timeout: 15000 });
await page.getByRole('link', { name: 'Settings & Schedule' }).click();
await page.getByRole('button', { name: 'Update storage settings' }).click();
await expect(page.locator('form')).toContainText('Settings updated', { timeout: 30000 });
await page.getByRole('button', { name: 'Update schedule' }).click();
await expect(page.locator('#app')).toContainText('Schedule updated');
await page.locator('div').filter({ hasText: /^Change passwordAdd new applicationLog out$/ }).getByRole('img').click();
await page.getByText('Log out', { exact: true }).click();
await expect(page.getByPlaceholder('password')).toBeVisible({ timeout: 30000 });
await expect(page.locator('#app')).toContainText('Enter the password to access the App Name admin console.');
await expect(page.getByRole('button')).toContainText('Log in');
});
Loading