diff --git a/.github/workflows/docs-tests.yml b/.github/workflows/docs-tests.yml new file mode 100644 index 000000000000..7026cf312734 --- /dev/null +++ b/.github/workflows/docs-tests.yml @@ -0,0 +1,40 @@ +name: Docs UI Tests + +on: + schedule: + - cron: '0 15 * * *' # Runs daily at 10:00 AM EST / 15:00 UTC + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Install dependencies + run: npm install + + - name: Install Playwright browsers + run: npx playwright install --with-deps + + - name: Set environment variables from GitHub Secrets + run: | + echo "ENV_APP_USERNAME=${{ secrets.ENV_APP_USERNAME }}" >> $GITHUB_ENV + echo "ENV_APP_PASSWORD=${{ secrets.ENV_APP_PASSWORD }}" >> $GITHUB_ENV + + - name: Run Playwright tests + run: npx playwright test --trace on + + - name: Send Slack notification on failure + if: failure() + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo, action, workflow + env: + SLACK_WEBHOOK_URL: ${{ secrets.DOCS_TESTS_SLACK_WEBHOOK }} + + - name: Cleanup app-auth.json + if: always() + run: rm -f ${{ github.workspace }}/app-auth.json \ No newline at end of file diff --git a/docs-tests/.gitignore b/docs-tests/.gitignore new file mode 100644 index 000000000000..4892497b87de --- /dev/null +++ b/docs-tests/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +.env \ No newline at end of file diff --git a/docs-tests/Dockerfile b/docs-tests/Dockerfile new file mode 100644 index 000000000000..6c79f0cf56e8 --- /dev/null +++ b/docs-tests/Dockerfile @@ -0,0 +1,8 @@ +FROM mcr.microsoft.com/playwright:v1.49.1-jammy + +WORKDIR /app +COPY . /app + +RUN npm install + +CMD ["npx", "playwright", "test", "--headed"] \ No newline at end of file diff --git a/docs-tests/package-lock.json b/docs-tests/package-lock.json new file mode 100644 index 000000000000..72a6d62050df --- /dev/null +++ b/docs-tests/package-lock.json @@ -0,0 +1,112 @@ +{ + "name": "docs-tests", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "docs-tests", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^16.4.7" + }, + "devDependencies": { + "@playwright/test": "^1.49.1", + "@types/node": "^22.10.2" + } + }, + "node_modules/@playwright/test": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", + "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.49.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", + "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.49.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", + "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/docs-tests/package.json b/docs-tests/package.json new file mode 100644 index 000000000000..a4ffdb49479a --- /dev/null +++ b/docs-tests/package.json @@ -0,0 +1,17 @@ +{ + "name": "docs-tests", + "version": "1.0.0", + "main": "index.js", + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "devDependencies": { + "@playwright/test": "^1.49.1", + "@types/node": "^22.10.2" + }, + "dependencies": { + "dotenv": "^16.4.7" + } +} diff --git a/docs-tests/playwright.config.ts b/docs-tests/playwright.config.ts new file mode 100644 index 000000000000..053a73ab5d8f --- /dev/null +++ b/docs-tests/playwright.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + workers: 1, + globalSetup: 'tests/globalSetup.ts', + use: { + storageState: 'app-auth.json', + }, +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleAddCompanyOwner.spec.js b/docs-tests/tests/adminConsoleAddCompanyOwner.spec.js new file mode 100644 index 000000000000..c0232da54ebb --- /dev/null +++ b/docs-tests/tests/adminConsoleAddCompanyOwner.spec.js @@ -0,0 +1,42 @@ +// This test verifies https://docs.docker.com/admin/company/owners/#add-a-company-owner + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleAddCompanyOwner", async ({ page }) => { + // Select Admin Console and choose company + await page.getByTestId("dashboard-card-admin").click(); + await page.getByRole("menuitem", { name: "sarahscompany Company" }).click(); + + // Select Company owners + await page.getByRole("menuitem", { name: "Company owners" }).click(); + + // Select Add owner and search for owner by Docker ID + await page.getByRole("button", { name: "Add owner" }).click(); + await page.getByLabel("Search by Docker ID").click(); + await page.getByLabel("Search by Docker ID").fill("sarahstestaccount"); + + // Verify Add company owner button exists + await expect( + page.getByRole("button", { name: "Add company owner" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleAddDBCMinutes.spec.js b/docs-tests/tests/adminConsoleAddDBCMinutes.spec.js new file mode 100644 index 000000000000..93b4e4d9ee74 --- /dev/null +++ b/docs-tests/tests/adminConsoleAddDBCMinutes.spec.js @@ -0,0 +1,44 @@ +// This test verifies https://docs.docker.com/subscription/scale/#add-docker-build-cloud-minutes + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleAddDBCMinutes", async ({ page }) => { + // Select Billing and choose organization + await page.getByTestId("dashboard-card-billing-account-center").click(); + await page + .getByRole("menuitem", { name: "docs dat Docker Business" }) + .click(); + + // Select View build minutes + await page.getByRole("link", { name: "View build minutes" }).click(); + + // Skip DBC pop-up + await page.getByRole("button", { name: "Skip" }).click(); + + // Select Purchase addiitonal minutes and choose amount + await page.getByRole("link", { name: "Purchase additional minutes" }).click(); + await page.getByLabel("build minutes | $50 $40").check(); + + // Select Continue to payment + await page.getByRole("button", { name: "Continue to payment" }).click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleAddOrganizationsToCompany.spec.js b/docs-tests/tests/adminConsoleAddOrganizationsToCompany.spec.js new file mode 100644 index 000000000000..8171d66a79f0 --- /dev/null +++ b/docs-tests/tests/adminConsoleAddOrganizationsToCompany.spec.js @@ -0,0 +1,39 @@ +// This test verifies https://docs.docker.com/admin/company/organizations/#add-organizations-to-a-company + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleAddOrganizationsToCompany", async ({ page }) => { + // Select Admin Console and choose company + await page.getByTestId("dashboard-card-admin").click(); + await page.getByRole("menuitem", { name: "sarahscompany Company" }).click(); + + // Select Add organization + await page.getByRole("button", { name: "Add organization" }).click(); + + // Choose organization to add from menu + await page.getByLabel("Open", { exact: true }).click(); + await page.getByTestId("add-sarahdat-to-co-menu-item").click(); + + // Verify Submit button present + await expect(page.getByTestId("add-org-submit-button")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleAddSeats.spec.js b/docs-tests/tests/adminConsoleAddSeats.spec.js new file mode 100644 index 000000000000..b3a8799254e5 --- /dev/null +++ b/docs-tests/tests/adminConsoleAddSeats.spec.js @@ -0,0 +1,50 @@ +// This test verifies https://docs.docker.com/subscription/manage-seats/#add-seats +// and https://docs.docker.com/subscription/manage-seats/#add-seats + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleAddSeats", async ({ page }) => { + // Select Billing and choose organization + await page.getByTestId("dashboard-card-billing-account-center").click(); + await page + .getByRole("menuitem", { name: "docs dat Docker Business" }) + .click(); + + // Select Add seats + await page.getByRole("link", { name: "Add seats" }).click(); + + // Specify number of seats to add and select Continue to billing + await page.getByRole("textbox").fill("10"); + await page.goto( + "https://app-stage.docker.com/billing/sarahdat/update/quantity/plan?add=10" + ); + await page.getByRole("link", { name: "Continue to billing" }).click(); + + // Select Continue to payment + await page.getByRole("link", { name: "Continue to payment" }).click(); + + // Verify Update subscription button is there + await expect( + page.getByRole("button", { name: "Update subscription" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleAddTeamMember.spec.js b/docs-tests/tests/adminConsoleAddTeamMember.spec.js new file mode 100644 index 000000000000..efa971d047c3 --- /dev/null +++ b/docs-tests/tests/adminConsoleAddTeamMember.spec.js @@ -0,0 +1,48 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#add-a-member-to-a-team + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleAddTeamMember", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select team tab and Select team name + await page.getByRole("menuitem", { name: "Teams" }).click(); + await page.getByRole("link", { name: "teamteam" }).click(); + + // Select Add member + await page.getByRole("button", { name: "Add member" }).click(); + + // Select a member from the drop down list + await page.getByLabel("Open", { exact: true }).click(); + await page.getByTestId("member-option-sarahsanders720").click(); + + // Verify Add button is there + await expect(page.getByRole("button", { name: "Add" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleChangeBillingCycle.spec.js b/docs-tests/tests/adminConsoleChangeBillingCycle.spec.js new file mode 100644 index 000000000000..39bcdb5cc654 --- /dev/null +++ b/docs-tests/tests/adminConsoleChangeBillingCycle.spec.js @@ -0,0 +1,37 @@ +// This test verifies https://docs.docker.com/billing/cycle/#personal-account +// and https://docs.docker.com/billing/cycle/#organization + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleChangeBillingCycle", async ({ page }) => { + // Select Billing Console and choose organization + await page.getByTestId("dashboard-card-billing-account-center").click(); + await page + .getByRole("menuitem", { name: "SS Sarah Sanders Docker Pro" }) + .click(); + + // Verify switch to annual billing is present + await expect( + page.getByRole("link", { name: "Switch to annual billing" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleConfigureImageAccessManagement.spec.js b/docs-tests/tests/adminConsoleConfigureImageAccessManagement.spec.js new file mode 100644 index 000000000000..5ad64f83a554 --- /dev/null +++ b/docs-tests/tests/adminConsoleConfigureImageAccessManagement.spec.js @@ -0,0 +1,40 @@ +// This test verifies https://docs.docker.com/security/for-admins/hardened-desktop/image-access-management/#configure + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleConfigureImageAccessManagement", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Choose Image access + await page.getByRole("menuitem", { name: "Image access" }).click(); + + // Verify Enable button exists + await expect(page.getByLabel("Disabled")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleConfigureRegistryAccessManagement.spec.js b/docs-tests/tests/adminConsoleConfigureRegistryAccessManagement.spec.js new file mode 100644 index 000000000000..1a26b82820da --- /dev/null +++ b/docs-tests/tests/adminConsoleConfigureRegistryAccessManagement.spec.js @@ -0,0 +1,55 @@ +// This test verifies https://docs.docker.com/security/for-admins/hardened-desktop/registry-access-management/#configure-registry-access-management-permissions + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleConfigureRegistryAccessManagement", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Choose Registry access + await page.getByRole("menuitem", { name: "Registry access" }).click(); + + // Enable Registry access management + const ramSwitch = page.getByTestId("ram-enabled-switch"); + if (!(await ramSwitch.isChecked())) { + await ramSwitch.check(); + } else { + console.log("Registry access management is already enabled."); + } + + // Select Add registry and enter registry details + await page.getByRole("button", { name: "Add registry" }).click(); + await page.getByLabel("Registry address *").click(); + await page.getByLabel("Registry address *").fill("docker"); + await page.getByLabel("Registry nickname *").click(); + await page.getByLabel("Registry nickname *").fill("test"); + + // Verify Create button exists + await expect(page.getByTestId("button-save")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleConvertAccount.spec.js b/docs-tests/tests/adminConsoleConvertAccount.spec.js new file mode 100644 index 000000000000..835b3933dd51 --- /dev/null +++ b/docs-tests/tests/adminConsoleConvertAccount.spec.js @@ -0,0 +1,33 @@ +// This test verifies https://docs.docker.com/admin/organization/convert-account/ + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleConvertAccount", async ({ page }) => { + // Select avatar menu and choose Account settings + await page.getByLabel("user menu sarahsanders720").click(); + await page.getByText("Account settings").click(); + + // Select Convert and verify Username and Confirm/Cancel buttons are present + await page.getByRole("menuitem", { name: "Convert" }).click(); + await expect(page.getByText("CancelConfirm")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleCreateCompany.spec.js b/docs-tests/tests/adminConsoleCreateCompany.spec.js new file mode 100644 index 000000000000..53c1699ddf02 --- /dev/null +++ b/docs-tests/tests/adminConsoleCreateCompany.spec.js @@ -0,0 +1,50 @@ +// This test verifies https://docs.docker.com/admin/company/new-company/#create-a-company + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleCreateCompany", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select Company management + await page.getByRole("menuitem", { name: "Company management" }).click(); + + // Select create company button and provide a company name + await page.getByTestId("create-company-button").click(); + await page.getByLabel("Company name").click(); + await page.getByLabel("Company name").fill("sarahdatcompany"); + + // Select Continue button + await page.getByRole("button", { name: "Continue" }).click(); + + // Verify billing flow + await expect( + page.getByRole("button", { name: "Create company" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleCreateOAT.spec.js b/docs-tests/tests/adminConsoleCreateOAT.spec.js new file mode 100644 index 000000000000..a8428d813614 --- /dev/null +++ b/docs-tests/tests/adminConsoleCreateOAT.spec.js @@ -0,0 +1,46 @@ +// This test verifies https://docs.docker.com/security/for-admins/access-tokens/#create-an-organization-access-token + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + } +}); + +test("adminConsoleCreateOAT", async ({ page }) => { + // Select Admin Console + await page.getByTestId("dashboard-card-admin").click(); + + // Wait for the organization menu item to be visible + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Wait for and click the "Access tokens" menu item + const accessTokensMenu = page.getByRole("menuitem", { + name: /Access tokens/, + }); + await expect(accessTokensMenu).toBeVisible(); + await accessTokensMenu.click(); + + // Verify that the "Generate access token" button is visible + const generateTokenLink = page.getByRole("link", { + name: "Generate access token", + }); + await expect(generateTokenLink).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleCreateOrganization.spec.js b/docs-tests/tests/adminConsoleCreateOrganization.spec.js new file mode 100644 index 000000000000..5656a8085710 --- /dev/null +++ b/docs-tests/tests/adminConsoleCreateOrganization.spec.js @@ -0,0 +1,31 @@ +// This test verifies https://docs.docker.com/admin/organization/orgs/#create-an-organization + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleCreateOrganization", async ({ page }) => { + // Select Admin Console + await page.getByTestId("dashboard-card-admin").click(); + + // On Choose profile page, click Create organization + await page.getByRole("menuitem", { name: "Create new organization" }).click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleCreatePAT.spec.js b/docs-tests/tests/adminConsoleCreatePAT.spec.js new file mode 100644 index 000000000000..bdeb74c8f145 --- /dev/null +++ b/docs-tests/tests/adminConsoleCreatePAT.spec.js @@ -0,0 +1,40 @@ +// This test verifies https://docs.docker.com/security/for-developers/access-tokens/#create-an-access-token + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleCreatePAT", async ({ page }) => { + // Select avatar and choose Account settings + await page.getByLabel('user menu sarahsanders720').click(); + + const accountSettings = page.getByText("Account settings"); + await expect(accountSettings).toBeVisible(); + await accountSettings.click(); + + // Select Personal access tokens and Generate new token + await page.getByRole("menuitem", { name: "Personal access tokens" }).click(); + + // Verify Generate button exists + await expect( + page.getByRole("link", { name: "Generate new token" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleCreateSettingsPolicy.spec.js b/docs-tests/tests/adminConsoleCreateSettingsPolicy.spec.js new file mode 100644 index 000000000000..60a8c5178cfb --- /dev/null +++ b/docs-tests/tests/adminConsoleCreateSettingsPolicy.spec.js @@ -0,0 +1,93 @@ +// This test verifies https://docs.docker.com/security/for-admins/hardened-desktop/settings-management/configure-admin-console/#create-a-settings-policy + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleCreateSettingsPolicy", async ({ page }) => { + // Select Admin Console and choose organization + const adminCard = page.getByTestId("dashboard-card-admin"); + await expect(adminCard).toBeVisible(); + await adminCard.click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select Docker Desktop Settings Management + await page.getByRole('menuitem', { name: 'Settings Management' }).click(); + + // Select Create a settings policy + const createPolicyLink = page.getByRole("link", { + name: "Create a settings policy", + }); + await expect(createPolicyLink).toBeVisible(); + await createPolicyLink.click(); + + // Give your settings policy a name and description + const policyNameField = page.getByLabel("Settings policy name"); + await expect(policyNameField).toBeVisible(); + await policyNameField.click(); + await policyNameField.fill("my policy"); + + const descriptionField = page.getByLabel("Description (optional)"); + await expect(descriptionField).toBeVisible(); + await descriptionField.click(); + await descriptionField.fill("my description"); + + // Assign the policy + const allUsersCheckbox = page.getByLabel("All users"); + await expect(allUsersCheckbox).toBeVisible(); + await allUsersCheckbox.check(); + + const selectedUsersCheckbox = page.getByLabel("Selected users"); + await expect(selectedUsersCheckbox).toBeVisible(); + await selectedUsersCheckbox.check(); + + const userAssignmentTextField = page.getByTestId("user-assignment-textfield"); + await expect(userAssignmentTextField).toBeVisible(); + await userAssignmentTextField.click(); + + const userOption = page + .getByTestId("user-option-sarahstestaccount") + .getByRole("checkbox"); + await expect(userOption).toBeVisible(); + await userOption.check(); + + // Configure settings + const usageStatsConfig = page + .getByTestId("Send usage statistics") + .getByLabel("Configuration"); + await expect(usageStatsConfig).toBeVisible(); + await usageStatsConfig.click(); + + const alwaysEnabledOption = page.getByRole("option", { + name: "Always enabled", + }); + await expect(alwaysEnabledOption).toBeVisible(); + await alwaysEnabledOption.click(); + + // Verify Create button exists + const submitButton = page.getByTestId("submit-button"); + await expect(submitButton).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleCreateTeam.spec.js b/docs-tests/tests/adminConsoleCreateTeam.spec.js new file mode 100644 index 000000000000..fa6f7b58b069 --- /dev/null +++ b/docs-tests/tests/adminConsoleCreateTeam.spec.js @@ -0,0 +1,40 @@ +// This test verifies https://docs.docker.com/admin/organization/manage-a-team/#create-a-team + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleCreateTeam", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select team tab and Select team name + await page.getByRole("menuitem", { name: "Teams" }).click(); + + // Verify Create team button is present + await expect(page.getByRole("button", { name: "Create team" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleDeactivateOrganization.spec.js b/docs-tests/tests/adminConsoleDeactivateOrganization.spec.js new file mode 100644 index 000000000000..c6cd59f31cfc --- /dev/null +++ b/docs-tests/tests/adminConsoleDeactivateOrganization.spec.js @@ -0,0 +1,34 @@ +// This test verifies https://docs.docker.com/admin/deactivate-account/#deactivate + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleDeactivateOrganization", async ({ page }) => { + // Select avatar menu and choose Account settings + await page.getByLabel("user menu sarahsanders720").click(); + await page.getByText("Account settings").click(); + + // Verify Deactivate button is present + await expect( + page.getByRole("menuitem", { name: "Deactivate" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleDeleteTeam.spec.js b/docs-tests/tests/adminConsoleDeleteTeam.spec.js new file mode 100644 index 000000000000..72be708e2eaf --- /dev/null +++ b/docs-tests/tests/adminConsoleDeleteTeam.spec.js @@ -0,0 +1,50 @@ +// This test verifies https://docs.docker.com/admin/organization/manage-a-team/#delete-a-team + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible().catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleDeleteTeam", async ({ page }) => { + // Select Admin Console and choose organization + const adminCard = page.getByTestId("dashboard-card-admin"); + await expect(adminCard).toBeVisible(); + await adminCard.click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select Teams + const teamsMenuItem = page.getByRole("menuitem", { name: "Teams" }); + await expect(teamsMenuItem).toBeVisible(); + await teamsMenuItem.click(); + + // Select actions menu + const teamActionsButton = page.getByTestId("team-actions-button-teamteam"); + await expect(teamActionsButton).toBeVisible(); + await teamActionsButton.click(); + + // Verify the Delete button is present + const deleteMenuItem = page.getByRole("menuitem", { name: "Delete" }); + await expect(deleteMenuItem).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleDowngradeSubscription.spec.js b/docs-tests/tests/adminConsoleDowngradeSubscription.spec.js new file mode 100644 index 000000000000..b8ad8528c82b --- /dev/null +++ b/docs-tests/tests/adminConsoleDowngradeSubscription.spec.js @@ -0,0 +1,39 @@ +// This test verifies https://docs.docker.com/subscription/change/#downgrade-your-subscription + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleDowngradeSubscription", async ({ page }) => { + // Select Billing and choose organization + await page.getByTestId("dashboard-card-billing-account-center").click(); + await page + .getByRole("menuitem", { name: "docs dat Docker Business" }) + .click(); + + // Select Action menu + await page.getByRole("group").getByRole("button").click(); + + // Verify Cancel subscription button is there + await expect( + page.getByRole("link", { name: "Cancel subscription" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleEnforceSSO.spec.js b/docs-tests/tests/adminConsoleEnforceSSO.spec.js new file mode 100644 index 000000000000..7d74117df781 --- /dev/null +++ b/docs-tests/tests/adminConsoleEnforceSSO.spec.js @@ -0,0 +1,55 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/connect/#optional-enforce-sso + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleEnforceSSO", async ({ page }) => { + // Select Admin Console and choose organization + const adminCard = page.getByTestId("dashboard-card-admin"); + await expect(adminCard).toBeVisible(); + await adminCard.click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select SSO and SCIM + await page + .getByRole("menuitem", { name: "SSO and SCIM" }) + .scrollIntoViewIfNeeded(); + await page.getByRole("menuitem", { name: "SSO and SCIM" }).click(); + + // Select SSO connection action button + const ssoConnectionButton = page.getByTestId( + "sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587" + ); + await expect(ssoConnectionButton).toBeVisible(); + await ssoConnectionButton.click(); + + // Verify Enable enforcement button is present + const enableEnforcement = page.getByRole("menuitem", { + name: "Enable enforcement", + }); + await expect(enableEnforcement).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleExportMembersCSV.spec.js b/docs-tests/tests/adminConsoleExportMembersCSV.spec.js new file mode 100644 index 000000000000..ef3370ecab33 --- /dev/null +++ b/docs-tests/tests/adminConsoleExportMembersCSV.spec.js @@ -0,0 +1,36 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#export-members-csv-file + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleExportMembersCSV", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Assert download button is visible + await expect(page.getByLabel("Export members")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleInviteCompanyMembers.spec.js b/docs-tests/tests/adminConsoleInviteCompanyMembers.spec.js new file mode 100644 index 000000000000..8283113981f0 --- /dev/null +++ b/docs-tests/tests/adminConsoleInviteCompanyMembers.spec.js @@ -0,0 +1,55 @@ +// This test verifies https://docs.docker.com/admin/company/users/#invite-members-via-docker-id-or-email-address + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleInviteCompanyMembers", async ({ page }) => { + // Select Admin Console and choose company + const dashboardAdmin = page.getByTestId("dashboard-card-admin"); + await expect(dashboardAdmin).toBeVisible(); + await dashboardAdmin.click(); + + const companyMenu = page.getByRole("menuitem", { + name: "sarahscompany Company", + }); + await expect(companyMenu).toBeVisible(); + await companyMenu.click(); + + // Select Users + const userManagementMenu = page.getByRole("menuitem", { + name: "User management", + }); + const usersMenuItem = page.getByRole("menuitem", { name: "Users" }); + if (!(await usersMenuItem.isVisible().catch(() => false))) { + await userManagementMenu.click(); + } else await expect(usersMenuItem).toBeVisible(); + await usersMenuItem.click(); + + // Select Invite and choose Emails or usernames + const inviteButton = page.getByRole("button", { name: "Invite" }); + await expect(inviteButton).toBeVisible(); + await inviteButton.click(); + + const inviteViaEmail = page.getByLabel("Invite members via email"); + await expect(inviteViaEmail).toBeVisible(); + await inviteViaEmail.click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/adminConsoleInviteCompanyMembersCSV.spec.js b/docs-tests/tests/adminConsoleInviteCompanyMembersCSV.spec.js new file mode 100644 index 000000000000..651f2a2b3e29 --- /dev/null +++ b/docs-tests/tests/adminConsoleInviteCompanyMembersCSV.spec.js @@ -0,0 +1,51 @@ +// This test verifies https://docs.docker.com/admin/company/users/#invite-members-via-csv-file + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible().catch(() => false)) { + await acceptCookies.click(); + } +}); + +test("adminConsoleInviteCompanyMembersCSV", async ({ page }) => { + // Select Admin Console and choose company + const adminConsole = page.getByTestId("dashboard-card-admin"); + await expect(adminConsole).toBeVisible(); + await adminConsole.click(); + + const companyMenuItem = page.getByRole("menuitem", { + name: "sarahscompany Company", + }); + await expect(companyMenuItem).toBeVisible(); + await companyMenuItem.click(); + + // Select Users + const userManagementMenu = page.getByRole("menuitem", { + name: "User management", + }); + const usersMenuItem = page.getByRole("menuitem", { name: "Users" }); + if (!(await usersMenuItem.isVisible().catch(() => false))) { + await userManagementMenu.click(); + } else + await expect(usersMenuItem).toBeVisible(); + await usersMenuItem.click(); + + // Select Invite and verify CSV upload is present + const inviteButton = page.getByRole("button", { name: "Invite" }); + await expect(inviteButton).toBeVisible(); + await inviteButton.click(); + await expect(page.getByLabel("Invite members via a CSV file")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/adminConsoleInviteMembers.spec.js b/docs-tests/tests/adminConsoleInviteMembers.spec.js new file mode 100644 index 000000000000..34cf147ab086 --- /dev/null +++ b/docs-tests/tests/adminConsoleInviteMembers.spec.js @@ -0,0 +1,57 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#invite-members-via-docker-id-or-email-address +// and https://docs.docker.com/security/for-admins/single-sign-on/manage/#add-guest-users-when-sso-is-enabled + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleInviteMembers", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Click Invite + await page.getByRole("button", { name: "Invite" }).click(); + + // Choose to invite by emails or usernames + await page.getByLabel("Invite members via email").click(); + + // Enter username or email and select role + await page.getByLabel("Enter username or email").click(); + await page.getByLabel("Enter username or email").fill("invitee@test.com"); + await page.getByLabel("Select a role").click(); + await page.getByRole("option", { name: "Member Non-administrative" }).click(); + + // Ensure dropdown is attached and stable before clicking + const teamSelect = page.getByTestId("create-team-select"); + await teamSelect.waitFor({ state: "visible", timeout: 10000 }); + await page.waitForTimeout(500); + + // Click the team select dropdown + await teamSelect.click(); + + // Assert invite button is visible + await expect(page.getByTestId("invite-member-modal-invite")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleManageOrganization.spec.js b/docs-tests/tests/adminConsoleManageOrganization.spec.js new file mode 100644 index 000000000000..4565ecea28f7 --- /dev/null +++ b/docs-tests/tests/adminConsoleManageOrganization.spec.js @@ -0,0 +1,28 @@ +// This test verifies https://docs.docker.com/admin/company/organizations/#manage-an-organization + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleManageOrganization", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleManagePaymentMethod.spec.js b/docs-tests/tests/adminConsoleManagePaymentMethod.spec.js new file mode 100644 index 000000000000..1c14119acb9f --- /dev/null +++ b/docs-tests/tests/adminConsoleManagePaymentMethod.spec.js @@ -0,0 +1,40 @@ +// This test verifies https://docs.docker.com/billing/payment-method/#organization + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleManagePaymentMethod", async ({ page }) => { + // Select Billing Console and choose organization + await page.getByTestId("dashboard-card-billing-account-center").click(); + await page + .getByRole("menuitem", { name: "docs dat Docker Business" }) + .click(); + + // Select Payment methods and choose Add payment method + await page.getByRole("menuitem", { name: "Payment methods" }).click(); + await page.getByRole("link", { name: "Add payment method" }).click(); + + // Verify Add payment method button is present + await expect( + page.getByRole("button", { name: "Add payment method" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleModifyOAT.spec.js b/docs-tests/tests/adminConsoleModifyOAT.spec.js new file mode 100644 index 000000000000..f23ef74f61e8 --- /dev/null +++ b/docs-tests/tests/adminConsoleModifyOAT.spec.js @@ -0,0 +1,53 @@ +// This test verifies https://docs.docker.com/security/for-admins/access-tokens/#modify-existing-tokens + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleModifyOAT", async ({ page }) => { + // Select Admin Console + await page.getByTestId("dashboard-card-admin").click(); + + // Select organization + await page + .getByRole("menuitem", { name: "docs dat Docker Business" }) + .click(); + + // Select Access tokens from left-nav + await page + .getByRole("menuitem", { name: "Access tokens New" }) + .scrollIntoViewIfNeeded(); + await page.getByRole("menuitem", { name: "Access tokens New" }).click(); + + // Select actions button + await page.getByRole('cell', { name: 'token-0-actions-menu' }).click(); + + // Verify Deactivate button is there + await expect( + page.getByRole("menuitem", { name: "Deactivate" }) + ).toBeVisible(); + + // Verify Edit button is there + await expect(page.getByRole("menuitem", { name: "Edit" })).toBeVisible(); + + // Verify Delete button is there + await expect(page.getByRole("menuitem", { name: "Delete" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/adminConsoleModifyPAT.spec.js b/docs-tests/tests/adminConsoleModifyPAT.spec.js new file mode 100644 index 000000000000..c99600e43911 --- /dev/null +++ b/docs-tests/tests/adminConsoleModifyPAT.spec.js @@ -0,0 +1,48 @@ +// This test verifies https://docs.docker.com/security/for-developers/access-tokens/#modify-existing-tokens + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleModifyPAT", async ({ page }) => { + // Select avatar and choose Account settings + const avatarButton = page.getByLabel("user menu sarahsanders720"); + await expect(avatarButton).toBeVisible(); + await avatarButton.click(); + + const accountSettings = page.getByText("Account settings"); + await expect(accountSettings).toBeVisible(); + await accountSettings.click(); + + // Select Personal access tokens + await page.getByRole("menuitem", { name: "Personal access tokens" }).click(); + + // Select actions menu and Edit + await page + .getByTestId("pat-menu-button-83f8d7e2-65a0-401e-b836-0362cddf794b") + .click(); + await page.getByRole("menuitem", { name: "Edit" }).click(); + await page.getByLabel("Access token description").click(); + await page.getByLabel("Access token description").fill("newpat1"); + + // Verify Generate button exists + await expect(page.getByRole("button", { name: "Save token" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleRemoveCompanyOwner.spec.js b/docs-tests/tests/adminConsoleRemoveCompanyOwner.spec.js new file mode 100644 index 000000000000..c51b34610c36 --- /dev/null +++ b/docs-tests/tests/adminConsoleRemoveCompanyOwner.spec.js @@ -0,0 +1,40 @@ +// This test verifies https://docs.docker.com/admin/company/owners/#remove-a-company-owner + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleRemoveCompanyOwner", async ({ page }) => { + // Select Admin Console and choose company + await page.getByTestId("dashboard-card-admin").click(); + await page.getByRole("menuitem", { name: "sarahscompany Company" }).click(); + + // Select Company owners + await page.getByRole("menuitem", { name: "Company owners" }).click(); + + // Select action menu + await page.getByTestId("company-owner-button-sarahstestaccount").click(); + + // Verify Remove company owner button exists + await expect( + page.getByRole("menuitem", { name: "Remove as company owner" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleRemoveInvitation.spec.js b/docs-tests/tests/adminConsoleRemoveInvitation.spec.js new file mode 100644 index 000000000000..1ef3b98e0907 --- /dev/null +++ b/docs-tests/tests/adminConsoleRemoveInvitation.spec.js @@ -0,0 +1,60 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#remove-an-invitation + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleRemoveInvitation", async ({ page }) => { + // Select Admin Console and choose organization + const adminCard = page.getByTestId("dashboard-card-admin"); + await expect(adminCard).toBeVisible(); + await adminCard.click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select Members + const membersMenuItem = page.getByRole("menuitem", { name: "Members" }); + await expect(membersMenuItem).toBeVisible(); + await membersMenuItem.click(); + + const inviteRow = page.getByRole("row", { + name: "-- -- sarahsanderstestinvite@", + }); + await expect(inviteRow).toBeVisible(); + + // Open the actions menu + const actionsMenu = inviteRow.getByLabel("Member actions menu"); + await expect(actionsMenu).toBeVisible(); + await actionsMenu.click(); + + // Click Remove in the actions dropdown + const removeMenuItem = page.getByRole("menuitem", { name: "Remove" }); + await expect(removeMenuItem).toBeVisible(); + await removeMenuItem.click(); + + // Verify that the Remove button is visible + const removeButton = page.getByRole("button", { name: "Remove" }); + await expect(removeButton).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleRemoveSeats.spec.js b/docs-tests/tests/adminConsoleRemoveSeats.spec.js new file mode 100644 index 000000000000..7a944404f5f4 --- /dev/null +++ b/docs-tests/tests/adminConsoleRemoveSeats.spec.js @@ -0,0 +1,52 @@ +// This test verifies https://docs.docker.com/subscription/manage-seats/#remove-seats + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible().catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleRemoveSeats", async ({ page }) => { + // Select Billing Console and choose organization + await page.getByTestId("dashboard-card-billing-account-center").click(); + await page + .getByRole("menuitem", { name: "docs dat Docker Business" }) + .click(); + + // Select action menu and choose Remove seats + const addSeatsButton = page.getByTestId("add-seats-action-button"); + await expect(addSeatsButton).toBeVisible(); + await addSeatsButton.click(); + await page.getByTestId("remove-seats-button").click(); + + // Select number of seats to remove + const seatTextbox = page.getByRole("textbox"); + await expect(seatTextbox).toBeVisible(); + await seatTextbox.click(); + await seatTextbox.fill("1"); + await page.goto( + "https://app-stage.docker.com/billing/sarahdat/update/quantity/plan?remove=1", + { waitUntil: "networkidle", timeout: 60000 } + ); + + // Verify Update subscription button exists + await expect( + page.getByRole("button", { name: "Update subscription" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleRemoveTeamMember.spec.js b/docs-tests/tests/adminConsoleRemoveTeamMember.spec.js new file mode 100644 index 000000000000..34ed330f13e7 --- /dev/null +++ b/docs-tests/tests/adminConsoleRemoveTeamMember.spec.js @@ -0,0 +1,44 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#remove-a-member-from-a-team +// and https://docs.docker.com/security/for-admins/single-sign-on/manage/#remove-users-from-the-sso-company + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleRemoveTeamMember", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select team tab and Select team name + await page.getByRole("menuitem", { name: "Teams" }).click(); + await page.getByRole("link", { name: "teamteam" }).click(); + + // Verify Remove from team button is there + await expect( + page.getByTestId("member-remove-button-sarahstestaccount") + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleResendInvitation.spec.js b/docs-tests/tests/adminConsoleResendInvitation.spec.js new file mode 100644 index 000000000000..c3193c80b102 --- /dev/null +++ b/docs-tests/tests/adminConsoleResendInvitation.spec.js @@ -0,0 +1,45 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#resend-an-invitation + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleResendInvitation", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select actions button and select Resend + await page.getByRole("menuitem", { name: "Members" }).click(); + await page + .getByRole("row", { name: "-- -- sarahsanderstestinvite@" }) + .getByLabel("Member actions menu") + .click(); + await page.getByRole("menuitem", { name: "Resend" }).click(); + + // Verify Remove button is there + await expect(page.getByRole("button", { name: "Invite" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSOAddDomain.spec.js b/docs-tests/tests/adminConsoleSSOAddDomain.spec.js new file mode 100644 index 000000000000..ee693cad6a35 --- /dev/null +++ b/docs-tests/tests/adminConsoleSSOAddDomain.spec.js @@ -0,0 +1,57 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/configure/#step-one-add-your-domain + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible().catch(() => false)) { + await acceptCookies.click(); + } +}); + +test("adminConsoleSSOAddDomain", async ({ page }) => { + // Select Admin Console + const adminCard = page.getByTestId("dashboard-card-admin"); + await expect(adminCard).toBeVisible(); + await adminCard.click(); + + // Wait for and click the organization menu item + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await Promise.all([ + page.waitForNavigation({ waitUntil: "networkidle" }), + orgMenuItem.click(), + ]); + + // Select Domain management + const domainManagement = page.getByRole("menuitem", { + name: "Domain management", + }); + await expect(domainManagement).toBeVisible(); + await domainManagement.click(); + + // Select Add a domain + const addDomainButton = page.getByRole("button", { name: "Add a domain" }); + await expect(addDomainButton).toBeVisible(); + await addDomainButton.click(); + + // Enter domain in text box and verify the Add domain submit button exists + const domainInput = page.getByLabel("Domain", { exact: true }); + await expect(domainInput).toBeVisible(); + await domainInput.fill("mydomain.com"); + + await expect(page.getByTestId("add-domain-submit-button")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSOAddGuestUsers.spec.js b/docs-tests/tests/adminConsoleSSOAddGuestUsers.spec.js new file mode 100644 index 000000000000..fe56fd0d3e44 --- /dev/null +++ b/docs-tests/tests/adminConsoleSSOAddGuestUsers.spec.js @@ -0,0 +1,45 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/manage/#add-guest-users-when-sso-is-enabled + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleSSOAddGuestUsers", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select Domain management + await page.getByRole("menuitem", { name: "Domain management" }).click(); + + // Select Add a domain + await page.getByRole("button", { name: "Add a domain" }).click(); + + // Enter domain in text box and verify Add domain button exists + await page.getByLabel("Domain", { exact: true }).click(); + await page.getByLabel("Domain", { exact: true }).fill("mydomain.com"); + await expect(page.getByTestId("add-domain-submit-button")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSOAuditDomains.spec.js b/docs-tests/tests/adminConsoleSSOAuditDomains.spec.js new file mode 100644 index 000000000000..b3aa8ba9ff4a --- /dev/null +++ b/docs-tests/tests/adminConsoleSSOAuditDomains.spec.js @@ -0,0 +1,37 @@ +// This test verifies https://docs.docker.com/security/for-admins/domain-audit/#audit-your-domains-for-uncaptured-users + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleSSOAuditDomains", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select Domain audit + await page.getByRole("menuitem", { name: "Domain audit" }).click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSODeleteConnection.spec.js b/docs-tests/tests/adminConsoleSSODeleteConnection.spec.js new file mode 100644 index 000000000000..8e2721e66ed8 --- /dev/null +++ b/docs-tests/tests/adminConsoleSSODeleteConnection.spec.js @@ -0,0 +1,54 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/manage/#delete-a-connection + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleSSODeleteConnection", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select SSO and SCIM + await page + .getByRole("menuitem", { name: "SSO and SCIM" }) + .scrollIntoViewIfNeeded(); + await page.getByRole("menuitem", { name: "SSO and SCIM" }).click(); + + // Wait for SSO connection list to load + const ssoButton = page.getByTestId( + "sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587" + ); + await ssoButton.waitFor({ state: "visible" }); + await ssoButton.click(); + + // Select action menu and then Delete connection + const deleteButton = page.getByRole("menuitem", { + name: "Delete connection", + }); + await deleteButton.waitFor({ state: "visible" }); + await deleteButton.click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSODisableJIT.spec.js b/docs-tests/tests/adminConsoleSSODisableJIT.spec.js new file mode 100644 index 000000000000..ff16eea62155 --- /dev/null +++ b/docs-tests/tests/adminConsoleSSODisableJIT.spec.js @@ -0,0 +1,48 @@ +// This test verifies https://docs.docker.com/security/for-admins/provisioning/just-in-time/#disable-jit-provisioning + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleSSODisableJIT", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select SSO and SCIM + await page + .getByRole("menuitem", { name: "SSO and SCIM" }) + .scrollIntoViewIfNeeded(); + await page.getByRole("menuitem", { name: "SSO and SCIM" }).click(); + + // Select action menu and select Verify Disable JIT provisioning is present + await page + .getByTestId("sso-connection-button-d628fde4-179e-4dd9-bb03-6da663f6c108") + .click(); + await expect( + page.getByRole("menuitem", { name: "Disable JIT provisioning" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSODisableSCIM.spec.js b/docs-tests/tests/adminConsoleSSODisableSCIM.spec.js new file mode 100644 index 000000000000..02d113182c6a --- /dev/null +++ b/docs-tests/tests/adminConsoleSSODisableSCIM.spec.js @@ -0,0 +1,49 @@ +// This test verifies https://docs.docker.com/security/for-admins/provisioning/scim/#disable-scim + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleSSODisableSCIM", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select SSO and SCIM + await page + .getByRole("menuitem", { name: "SSO and SCIM" }) + .scrollIntoViewIfNeeded(); + await page.getByRole("menuitem", { name: "SSO and SCIM" }).click(); + + // Select action menu + await page + .getByTestId("sso-connection-button-d628fde4-179e-4dd9-bb03-6da663f6c108") + .click(); + + // Verify Disable SCIM is present + await expect( + page.getByRole("menuitem", { name: "Disable SCIM" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSOEditConnection.spec.js b/docs-tests/tests/adminConsoleSSOEditConnection.spec.js new file mode 100644 index 000000000000..ad58026dc890 --- /dev/null +++ b/docs-tests/tests/adminConsoleSSOEditConnection.spec.js @@ -0,0 +1,50 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/manage/#connect-an-organization +// and https://docs.docker.com/security/for-admins/single-sign-on/manage/#remove-an-organization +// and https://docs.docker.com/security/for-admins/single-sign-on/manage/#edit-a-connection + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleSSOEditConnection", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select SSO and SCIM + await page + .getByRole("menuitem", { name: "SSO and SCIM" }) + .scrollIntoViewIfNeeded(); + await page.getByRole("menuitem", { name: "SSO and SCIM" }).click(); + + // Select action menu and then Edit connection + await page + .getByTestId("sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587") + .waitFor({ state: "visible", timeout: 30000 }); + await page + .getByTestId("sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587") + .click(); + await page.getByRole("menuitem", { name: "Edit connection" }).click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSOEnableSCIM.spec.js b/docs-tests/tests/adminConsoleSSOEnableSCIM.spec.js new file mode 100644 index 000000000000..a29c2f77b796 --- /dev/null +++ b/docs-tests/tests/adminConsoleSSOEnableSCIM.spec.js @@ -0,0 +1,52 @@ +// This test verifies https://docs.docker.com/security/for-admins/provisioning/scim/#enable-scim-in-docker + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleSSOEnableSCIM", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select SSO and SCIM + await page + .getByRole("menuitem", { name: "SSO and SCIM" }) + .scrollIntoViewIfNeeded(); + await page.getByRole("menuitem", { name: "SSO and SCIM" }).click(); + + // Select action menu and Enable SCIM + await page + .getByTestId("sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587") + .click(); + const enableScimMenuItem = page.getByRole("menuitem", { + name: "Enable SCIM", + }); + await expect(enableScimMenuItem).toBeVisible(); + await enableScimMenuItem.click(); + + // Verify Enable button is present + await expect(page.getByRole("button", { name: "Enable" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/adminConsoleSSORemoveDomain.spec.js b/docs-tests/tests/adminConsoleSSORemoveDomain.spec.js new file mode 100644 index 000000000000..f2fd1c583416 --- /dev/null +++ b/docs-tests/tests/adminConsoleSSORemoveDomain.spec.js @@ -0,0 +1,39 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/manage/#remove-a-domain-from-an-sso-connection + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleSSORemoveDomain", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select Domain management + await page.getByRole("menuitem", { name: "Domain management" }).click(); + + // Verify delete domain button exists + await expect(page.getByLabel("To remove this domain, remove")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSOVerifyDomain.spec.js b/docs-tests/tests/adminConsoleSSOVerifyDomain.spec.js new file mode 100644 index 000000000000..95d80cbf2c48 --- /dev/null +++ b/docs-tests/tests/adminConsoleSSOVerifyDomain.spec.js @@ -0,0 +1,52 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/configure/#step-two-verify-your-domain + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleSSOVerifyDomain", async ({ page }) => { + // Select Admin Console and choose organization + const adminCard = page.getByTestId("dashboard-card-admin"); + await expect(adminCard).toBeVisible(); + await adminCard.click(); + + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select Domain management + const securityAndAccessMenu = page.getByRole("menuitem", { + name: "Security and access", + }); + const domainManagementMenu = page.getByRole("menuitem", { + name: "Domain management", + }); + if (!(await domainManagementMenu.isVisible().catch(() => false))) { + await securityAndAccessMenu.click(); + } else await expect(domainManagementMenu).toBeVisible(); + await domainManagementMenu.click(); + + // Verify the Verify button is present + const verifyButton = page.getByTestId("verify-testverifydomain.com"); + await expect(verifyButton).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleSSOViewErrorLogs.spec.js b/docs-tests/tests/adminConsoleSSOViewErrorLogs.spec.js new file mode 100644 index 000000000000..7fc17d539cab --- /dev/null +++ b/docs-tests/tests/adminConsoleSSOViewErrorLogs.spec.js @@ -0,0 +1,56 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/troubleshoot/#view-sso-and-scim-error-logs + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + } +}); + +test("adminConsoleSSOViewErrorLogs", async ({ page }) => { + // Select Admin Console + const adminCard = page.getByTestId("dashboard-card-admin"); + await expect(adminCard).toBeVisible(); + await adminCard.click(); + + // Select organization and wait for the navigation to complete + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible({ timeout: 10000 }); + await Promise.all([ + page.waitForNavigation({ waitUntil: "networkidle" }), + orgMenuItem.click(), + ]); + + // Wait for and select "SSO and SCIM" + const ssoScimMenuItem = page.getByRole("menuitem", { name: "SSO and SCIM" }); + await expect(ssoScimMenuItem).toBeVisible({ timeout: 10000 }); + await ssoScimMenuItem.click(); + + // Open the action menu and click "View error logs" + const ssoConnectionButton = page.getByTestId( + "sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587" + ); + await expect(ssoConnectionButton).toBeVisible({ timeout: 10000 }); + await ssoConnectionButton.click(); + + const viewErrorLogsItem = page.getByRole("menuitem", { + name: "View error logs", + }); + await expect(viewErrorLogsItem).toBeVisible({ timeout: 10000 }); + await viewErrorLogsItem.click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleUpgradeSubscription.spec.js b/docs-tests/tests/adminConsoleUpgradeSubscription.spec.js new file mode 100644 index 000000000000..1eeb7f76ad7a --- /dev/null +++ b/docs-tests/tests/adminConsoleUpgradeSubscription.spec.js @@ -0,0 +1,34 @@ +// This test verifies https://docs.docker.com/subscription/change/#downgrade-your-subscription + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleDowngradeSubscription", async ({ page }) => { + // Select Billing and choose organization + await page.getByTestId("dashboard-card-billing-account-center").click(); + await page + .getByRole("menuitem", { name: "Manual Audit 2 Docker Free" }) + .click(); + + // Verify Upgrade button is there + await expect(page.getByRole("link", { name: "Upgrade" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleViewInsights.spec.js b/docs-tests/tests/adminConsoleViewInsights.spec.js new file mode 100644 index 000000000000..af9998ea9433 --- /dev/null +++ b/docs-tests/tests/adminConsoleViewInsights.spec.js @@ -0,0 +1,39 @@ +// This test verifies https://docs.docker.com/admin/organization/insights/#view-insights-for-organization-users + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleViewInsights", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select Desktop insights + await page + .getByTestId("layout-sidebar") + .getByTestId("insight-dashboard-link") + .click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/adminConsoleViewOrganizations.spec.js b/docs-tests/tests/adminConsoleViewOrganizations.spec.js new file mode 100644 index 000000000000..324820995cae --- /dev/null +++ b/docs-tests/tests/adminConsoleViewOrganizations.spec.js @@ -0,0 +1,39 @@ +// This test verifies https://docs.docker.com/admin/company/organizations/#view-all-organizations + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleViewOrganizations", async ({ page }) => { + // Select Admin Console and choose organization + await page.getByTestId("dashboard-card-admin").click(); + const orgMenuItem = page.getByRole("menuitem", { + name: "docs dat Docker Business", + }); + await expect(orgMenuItem).toBeVisible(); + await orgMenuItem.click(); + + // Select General + await page + .getByRole("menuitem", { name: "General" }) + .scrollIntoViewIfNeeded(); + await page.getByRole("menuitem", { name: "General" }).click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/adminConsoleViewRenewalDate.spec.js b/docs-tests/tests/adminConsoleViewRenewalDate.spec.js new file mode 100644 index 000000000000..fbd20c61d81c --- /dev/null +++ b/docs-tests/tests/adminConsoleViewRenewalDate.spec.js @@ -0,0 +1,39 @@ +// This test verifies https://docs.docker.com/billing/history/#view-renewal-date + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); + + // Accept cookies if visible + const acceptCookies = page.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } +}); + +test("adminConsoleViewRenewalDate", async ({ page }) => { + // Select Billing Console and choose organization + await page.getByTestId("dashboard-card-billing-account-center").click(); + await page + .getByRole("menuitem", { name: "docs dat Docker Business" }) + .click(); + + // Verify next bill date is present + await expect( + page + .locator("div") + .filter({ hasText: /^Next bill/ }) + .getByRole("paragraph") + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerAccountCreateID.spec.js b/docs-tests/tests/dockerAccountCreateID.spec.js new file mode 100644 index 000000000000..3794e7af4a7d --- /dev/null +++ b/docs-tests/tests/dockerAccountCreateID.spec.js @@ -0,0 +1,28 @@ +// This test verifies https://docs.docker.com/accounts/create-account/#create-a-docker-id + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test("dockerAccountCreateID", async ({ page }) => { + // Go to the Docker WWW and select Sign In + await page.goto("https://www.docker.com/"); + await page.getByRole("link", { name: "Sign In" }).click(); + + // Select Sign Up + await page.getByRole("link", { name: "Sign Up" }).click(); + + // Enter email, username, and password + await page.getByLabel("Email").click(); + await page.getByLabel("Email").fill("test4328798473298@customer.com"); + + await page.getByLabel("Username").click(); + await page.getByLabel("Username").fill("test934832094830"); + + const passwordInput = page.getByLabel("Password", { exact: true }); + await passwordInput.waitFor({ state: "visible", timeout: 5000 }); + await passwordInput.click(); + await passwordInput.fill("password543878432"); + + // Verify Sign up button is present + await expect(page.getByRole("button", { name: "Sign up" })).toBeVisible(); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerAccountSignupGitHub.spec.js b/docs-tests/tests/dockerAccountSignupGitHub.spec.js new file mode 100644 index 000000000000..ed12cf3662c0 --- /dev/null +++ b/docs-tests/tests/dockerAccountSignupGitHub.spec.js @@ -0,0 +1,18 @@ +// This test verifies https://docs.docker.com/accounts/create-account/#sign-up-with-google-or-github + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test("dockerAccountSignupGitHub", async ({ page }) => { + // Go to the Docker WWW and select Sign In + await page.goto("https://www.docker.com/"); + await page.getByRole("link", { name: "Sign In" }).click(); + + // Select Sign Up + await page.getByRole("link", { name: "Sign Up" }).click(); + + // Verify Sign up with GitHub button is present + await expect( + page.getByRole("link", { name: "Continue with GitHub" }) + ).toBeVisible(); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerAccountSignupGoogle.spec.js b/docs-tests/tests/dockerAccountSignupGoogle.spec.js new file mode 100644 index 000000000000..1582bc430ea8 --- /dev/null +++ b/docs-tests/tests/dockerAccountSignupGoogle.spec.js @@ -0,0 +1,18 @@ +// This test verifies https://docs.docker.com/accounts/create-account/#sign-up-with-google-or-github + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test("dockerAccountSignupGoogle", async ({ page }) => { + // Go to the Docker WWW and select Sign In + await page.goto("https://www.docker.com/"); + await page.getByRole("link", { name: "Sign In" }).click(); + + // Select Sign Up + await page.getByRole("link", { name: "Sign Up" }).click(); + + // Verify Sign up with GitHub button is present + await expect( + page.getByRole("link", { name: "Continue with Google" }) + ).toBeVisible(); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubAddSeats.spec.js b/docs-tests/tests/dockerHubAddSeats.spec.js new file mode 100644 index 000000000000..48cfc794efe2 --- /dev/null +++ b/docs-tests/tests/dockerHubAddSeats.spec.js @@ -0,0 +1,62 @@ +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubAddSeats", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + const dashboardHub = page.getByTestId("dashboard-card-hub"); + await expect(dashboardHub).toBeVisible({ timeout: 5000 }); + await dashboardHub.click(); + const page2 = await page2Promise; + await page2.waitForLoadState("networkidle"); + + // Select Billing + const acceptCookiesButton = page2.getByRole("button", { + name: "Accept All Cookies", + }); + await expect(acceptCookiesButton).toBeVisible({ timeout: 5000 }); + await acceptCookiesButton.click(); + + const layoutSidebarBilling = page2.getByTestId("layout-sidebar"); + await expect(layoutSidebarBilling).toBeVisible({ timeout: 5000 }); + const billingTab = layoutSidebarBilling.getByTestId("org-page-tab-billing"); + await expect(billingTab).toBeVisible({ timeout: 5000 }); + await billingTab.click(); + + // Select Docker Billing and choose organization + const page3Promise = page2.waitForEvent("popup"); + const dockerBillingLink = page2.getByRole("link", { + name: "Docker Billing⁠", + }); + await expect(dockerBillingLink).toBeVisible({ timeout: 5000 }); + await dockerBillingLink.click(); + const page3 = await page3Promise; + await page3.waitForLoadState("networkidle"); + + // Wait for the sidebar and user label to become visible in page3 + const layoutSidebar = page3.getByTestId("layout-sidebar"); + await expect(layoutSidebar).toBeVisible({ timeout: 5000 }); + + const userLabel = layoutSidebar.getByLabel("open context switcher"); + await expect(userLabel).toBeVisible({ timeout: 5000 }); + await userLabel.click(); + + const orgLink = layoutSidebar.locator("a").filter({ hasText: "sarahdat" }); + await expect(orgLink).toBeVisible({ timeout: 5000 }); + await orgLink.click(); + + // Verify the "Add seats" button exists + const addSeatsLink = page3.getByRole("link", { name: "Add seats" }); + await expect(addSeatsLink).toBeVisible({ timeout: 5000 }); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubAddTeamMember.spec.js b/docs-tests/tests/dockerHubAddTeamMember.spec.js new file mode 100644 index 000000000000..f3684479bb37 --- /dev/null +++ b/docs-tests/tests/dockerHubAddTeamMember.spec.js @@ -0,0 +1,52 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#add-a-member-to-a-team + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubAddTeamMember", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Members + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-members") + .click(); + + // Select actions menu + await page2 + .getByRole("row", { name: "sarahstestaccount Guest sarah" }) + .getByTestId("member-actions-menu-open") + .click(); + + // Select Add to team and choose team + await page2.getByRole("menuitem", { name: "Add to team" }).click(); + await page2.getByLabel("Open", { exact: true }).click(); + await page2.getByRole("option", { name: "testeam" }).click(); + + // Verify Add button exists + await expect(page2.getByRole("button", { name: "Add" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubChangeBillingCycle.spec.js b/docs-tests/tests/dockerHubChangeBillingCycle.spec.js new file mode 100644 index 000000000000..ece9c2735f12 --- /dev/null +++ b/docs-tests/tests/dockerHubChangeBillingCycle.spec.js @@ -0,0 +1,40 @@ +// This test verifies https://docs.docker.com/billing/cycle/#personal-account +// and https://docs.docker.com/billing/cycle/#organization + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubChangeBillingCycle", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select Billing + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-billing") + .click(); + + // Select Docker Billing + const page3Promise = page2.waitForEvent("popup"); + await page2.getByRole("link", { name: "Docker Billing⁠" }).click(); + const page3 = await page3Promise; + + // Verify switch to annual billing is present + await expect( + page3.getByRole("link", { name: "Switch to annual billing" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubConfigureImageAccessManagement.spec.js b/docs-tests/tests/dockerHubConfigureImageAccessManagement.spec.js new file mode 100644 index 000000000000..b3b93ad02f24 --- /dev/null +++ b/docs-tests/tests/dockerHubConfigureImageAccessManagement.spec.js @@ -0,0 +1,38 @@ +// This test verifies https://docs.docker.com/security/for-admins/hardened-desktop/image-access-management/#configure + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubConfigureImageAccessManagement", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Image Access + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Image Access" }).click(); + + // Verify Enable Image Access toggle exists + await expect(page2.getByLabel("Image Access Management")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubConfigureRegistryAccessManagement.spec.js b/docs-tests/tests/dockerHubConfigureRegistryAccessManagement.spec.js new file mode 100644 index 000000000000..cf9eb7090c97 --- /dev/null +++ b/docs-tests/tests/dockerHubConfigureRegistryAccessManagement.spec.js @@ -0,0 +1,45 @@ +// This test verifies https://docs.docker.com/security/for-admins/hardened-desktop/registry-access-management/#configure-registry-access-management-permissions + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubConfigureRegistryAccessManagement", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Registry Access + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Registry Access" }).click(); + + // Select Enable Registry Access toggle + await page2 + .locator("div") + .filter({ hasText: /^Disabled$/ }) + .getByRole("checkbox") + .check(); + + // Verify Save button exists + await expect(page2.getByRole("button", { name: "Save" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubConfigureRepoPermissions.spec.js b/docs-tests/tests/dockerHubConfigureRepoPermissions.spec.js new file mode 100644 index 000000000000..9b1f11266536 --- /dev/null +++ b/docs-tests/tests/dockerHubConfigureRepoPermissions.spec.js @@ -0,0 +1,53 @@ +// This test verifies https://docs.docker.com/admin/organization/manage-a-team/#configure-repository-permissions-for-a-team + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubConfigureRepoPermissions", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Teams + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-teams") + .click(); + + // Select a team + await page2.getByRole("link", { name: "teamteam" }).click(); + + // Select Permissions + await page2.getByTestId("permissions").click(); + + // Select repo and permission level + await page2.getByLabel("Open", { exact: true }).click(); + await page2.getByRole("option", { name: "sarahdatrepo" }).click(); + await page2.getByLabel("Permission").click(); + await page2.getByRole("option", { name: "Admin" }).click(); + + // Verify Remove button exists + await expect(page2.getByRole("button", { name: "Add" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubCreateOrganization.spec.js b/docs-tests/tests/dockerHubCreateOrganization.spec.js new file mode 100644 index 000000000000..0cae762fc09f --- /dev/null +++ b/docs-tests/tests/dockerHubCreateOrganization.spec.js @@ -0,0 +1,37 @@ +// This test verifies https://docs.docker.com/admin/organization/orgs/#create-an-organization + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubCreateOrganization", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organization drop-down + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + + // Verify Create organization button exists + await expect( + page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "Create organization" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubCreateRepository.spec.js b/docs-tests/tests/dockerHubCreateRepository.spec.js new file mode 100644 index 000000000000..dc0c77a9cfd5 --- /dev/null +++ b/docs-tests/tests/dockerHubCreateRepository.spec.js @@ -0,0 +1,39 @@ +// This test verifies https://docs.docker.com/get-started/introduction/build-and-push-first-image/#create-an-image-repository, +// https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-registry/#create-your-first-repository +// and https://docs.docker.com/get-started/workshop/04_sharing_app/#create-a-repository + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubCreateRepository", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page4Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page4 = await page4Promise; + + // Select Create repository + await page4.getByTestId("createRepoBtn").click(); + + // Enter a repository name, description, and select Public visibility + await page4.getByTestId("repoNameField-input").click(); + await page4 + .getByTestId("repoNameField-input") + .fill("getting-started-todo-app"); + await page4.getByTestId("repoDescriptionField-input").click(); + await page4.getByTestId("repoDescriptionField-input").fill("description"); + await page4.getByLabel("PublicAppears in Docker Hub").check(); + + // Verify Create button exists + await expect(page4.getByTestId("submit")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubCreateTeam.spec.js b/docs-tests/tests/dockerHubCreateTeam.spec.js new file mode 100644 index 000000000000..c8c1dc5b74ff --- /dev/null +++ b/docs-tests/tests/dockerHubCreateTeam.spec.js @@ -0,0 +1,48 @@ +// This test verifies https://docs.docker.com/admin/organization/manage-a-team/#create-a-team + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubCreateTeam", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Teams + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-teams") + .click(); + + // Select Create team and add team name + await page2.getByTestId("create-team-btn").click(); + await page2.getByTestId("form-create-team-input-team-name-input").click(); + await page2 + .getByTestId("form-create-team-input-team-name-input") + .fill("testteam"); + + // Verify Remove button exists + await expect(page2.getByTestId("form-create-team-btn-create")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubDeactivateOrganization.spec.js b/docs-tests/tests/dockerHubDeactivateOrganization.spec.js new file mode 100644 index 000000000000..e3b978e1a025 --- /dev/null +++ b/docs-tests/tests/dockerHubDeactivateOrganization.spec.js @@ -0,0 +1,46 @@ +// This test verifies https://docs.docker.com/admin/deactivate-account/#deactivate + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubDeactivateOrganization", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Settings + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-settings") + .click(); + + // Select Deactivate org + await page2.getByRole("menuitem", { name: "Deactivate org" }).click(); + + // Verify Deactive organization/account button exists + await expect( + page2.locator("div").filter({ hasText: /^Deactivate organization$/ }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubDeleteTeam.spec.js b/docs-tests/tests/dockerHubDeleteTeam.spec.js new file mode 100644 index 000000000000..c54bdbcb40eb --- /dev/null +++ b/docs-tests/tests/dockerHubDeleteTeam.spec.js @@ -0,0 +1,47 @@ +// This test verifies https://docs.docker.com/admin/organization/manage-a-team/#delete-a-team + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubDeleteTeam", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Teams + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-teams") + .click(); + + // Select a team + await page2.getByRole("link", { name: "teamteam" }).click(); + + // Select Settings + await page2.getByTestId("settings").click(); + + // Verify Delete team button exists + await expect(page2.getByTestId("btn-delete-team")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubDowngradeSubscription.spec.js b/docs-tests/tests/dockerHubDowngradeSubscription.spec.js new file mode 100644 index 000000000000..46e48efc2bae --- /dev/null +++ b/docs-tests/tests/dockerHubDowngradeSubscription.spec.js @@ -0,0 +1,79 @@ +// This test verifies https://docs.docker.com/billing/history/#view-renewal-date + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubDowngradeSubscription", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + await page2.waitForLoadState("load"); + + // Accept cookies if present + const acceptCookies = page2.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + } + + // Select organization + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + + // Navigate to Billing tab + const billingTab = page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-billing"); + await billingTab.waitFor({ state: "visible", timeout: 10000 }); + await billingTab.click(); + + // Open Docker Billing page + const page3Promise = page2.waitForEvent("popup"); + await page2.getByRole("link", { name: "Docker Billing⁠" }).click(); + const page3 = await page3Promise; + await page3.waitForLoadState("load"); + + // Ensure correct organization selection in Billing + await page3 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page3 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdat" }) + .click(); + + // Wait for the actions menu button to appear + const actionsMenu = page3.getByRole("group").getByRole("button"); + await actionsMenu.waitFor({ state: "visible", timeout: 10000 }); + console.log(await actionsMenu.isVisible()); + + // Click actions menu + await actionsMenu.click(); + + // Verify Cancel Subscription button is present + await expect( + page3.getByRole("link", { name: "Cancel subscription" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubEnforceSSO.spec.js b/docs-tests/tests/dockerHubEnforceSSO.spec.js new file mode 100644 index 000000000000..43d14d955240 --- /dev/null +++ b/docs-tests/tests/dockerHubEnforceSSO.spec.js @@ -0,0 +1,45 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/connect/#optional-enforce-sso + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubEnforceSSO", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Security + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Security" }).click(); + + // Select actions menu + await page2 + .getByTestId("sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587") + .click(); + + // Verify Enable enforcement button exists + await expect( + page2.getByRole("menuitem", { name: "Enable enforcement" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubExportMembersCSV.spec.js b/docs-tests/tests/dockerHubExportMembersCSV.spec.js new file mode 100644 index 000000000000..4e68058e71c8 --- /dev/null +++ b/docs-tests/tests/dockerHubExportMembersCSV.spec.js @@ -0,0 +1,43 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#export-members-csv-file + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubExportMembersCSV", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then members + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-members") + .click(); + + // Verify Export members button exists + await expect( + page2.getByRole("button", { name: "Export members" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubInviteMembers.spec.js b/docs-tests/tests/dockerHubInviteMembers.spec.js new file mode 100644 index 000000000000..3d347ea6f687 --- /dev/null +++ b/docs-tests/tests/dockerHubInviteMembers.spec.js @@ -0,0 +1,56 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#invite-members-via-docker-id-or-email-address + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubInviteMembers", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Members + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-members") + .click(); + + // Select Invite members + await page2.getByTestId("openAddMemberModal").click(); + + // Select Emails or usernames + await page2.getByLabel("Invite members via email").click(); + + // Type email and select role + await page2.getByLabel("Enter username or email").click(); + await page2.getByLabel("Enter username or email").fill("testinvite@user.com"); + await page2.getByLabel("Select a role").click(); + await page2 + .getByTestId("select-role-option-member") + .getByText("Member") + .click(); + + // Verify Invite button exists + await expect(page2.getByTestId("invite-member-modal-invite")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubInviteMembersCSV.spec.js b/docs-tests/tests/dockerHubInviteMembersCSV.spec.js new file mode 100644 index 000000000000..f8e0a230a554 --- /dev/null +++ b/docs-tests/tests/dockerHubInviteMembersCSV.spec.js @@ -0,0 +1,52 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#invite-members-via-csv-file + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubInviteMembersCSV", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Members + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-members") + .click(); + + // Select Invite members + await page2.getByTestId("openAddMemberModal").click(); + + // Select Invite by CSV + await page2.getByLabel("Invite members via a CSV file").click(); + + // Select Browse files and select a role + await page2.getByRole("button", { name: "Browse files" }).click(); + await page2.getByLabel("Select a role").click(); + await page2.getByTestId("select-role-option-member").click(); + + // Verify Review button exists + await expect(page2.getByLabel("Select a team and pick a file")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubManagePaymentMethod.spec.js b/docs-tests/tests/dockerHubManagePaymentMethod.spec.js new file mode 100644 index 000000000000..8935e54dfc48 --- /dev/null +++ b/docs-tests/tests/dockerHubManagePaymentMethod.spec.js @@ -0,0 +1,53 @@ +// This test verifies https://docs.docker.com/billing/payment-method/#personal-account +// and https://docs.docker.com/billing/payment-method/#organization + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubManagePaymentMethod", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Billing + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-billing") + .click(); + + // Select Docker Billing + const page3Promise = page2.waitForEvent("popup"); + await page2.getByRole("link", { name: "Docker Billing⁠" }).click(); + const page3 = await page3Promise; + + // Select Payment methods and choose Add payment method + await page3.getByRole("menuitem", { name: "Payment methods" }).click(); + await page3.getByRole("link", { name: "Add payment method" }).click(); + + // Verify Add payment method button is present + await expect( + page3.getByRole("button", { name: "Add payment method" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubRemoveInvitation.spec.js b/docs-tests/tests/dockerHubRemoveInvitation.spec.js new file mode 100644 index 000000000000..d515bfcf6266 --- /dev/null +++ b/docs-tests/tests/dockerHubRemoveInvitation.spec.js @@ -0,0 +1,49 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#remove-an-invitation + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubRemoveInvitation", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Members + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-members") + .click(); + + // Select actions menu + await page2 + .getByRole("row", { name: "sarahsanderstestinvite@docker" }) + .getByTestId("member-actions-menu-open") + .click(); + + // Verify Resend invitation button exists + await expect( + page2.getByRole("menuitem", { name: "Remove invitee" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubRemoveSeats.spec.js b/docs-tests/tests/dockerHubRemoveSeats.spec.js new file mode 100644 index 000000000000..6da885684978 --- /dev/null +++ b/docs-tests/tests/dockerHubRemoveSeats.spec.js @@ -0,0 +1,66 @@ +// This test verifies https://docs.docker.com/subscription/manage-seats/#remove-seats + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubRemoveSeats", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + const dashboardHub = page.getByTestId("dashboard-card-hub"); + await expect(dashboardHub).toBeVisible({ timeout: 5000 }); + await dashboardHub.click(); + const page2 = await page2Promise; + await page2.waitForLoadState("networkidle"); + + // Select Billing + const acceptCookiesButton = page2.getByRole("button", { + name: "Accept All Cookies", + }); + await expect(acceptCookiesButton).toBeVisible({ timeout: 5000 }); + await acceptCookiesButton.click(); + + const layoutSidebarBilling = page2.getByTestId("layout-sidebar"); + await expect(layoutSidebarBilling).toBeVisible({ timeout: 5000 }); + const billingTab = layoutSidebarBilling.getByTestId("org-page-tab-billing"); + await expect(billingTab).toBeVisible({ timeout: 5000 }); + await billingTab.click(); + + // Select Docker Billing and choose organization + const page3Promise = page2.waitForEvent("popup"); + const dockerBillingLink = page2.getByRole("link", { + name: "Docker Billing⁠", + }); + await expect(dockerBillingLink).toBeVisible({ timeout: 5000 }); + await dockerBillingLink.click(); + const page3 = await page3Promise; + await page3.waitForLoadState("networkidle"); + + // Wait for the sidebar and user label to become visible in page3 + const layoutSidebar = page3.getByTestId("layout-sidebar"); + await expect(layoutSidebar).toBeVisible({ timeout: 5000 }); + + const userLabel = layoutSidebar.getByLabel("open context switcher"); + await expect(userLabel).toBeVisible({ timeout: 5000 }); + await userLabel.click(); + + const orgLink = layoutSidebar.locator("a").filter({ hasText: "sarahdat" }); + await expect(orgLink).toBeVisible({ timeout: 5000 }); + await orgLink.click(); + + // Select action menu + await page3.getByTestId("add-seats-action-button").click(); + + // Verify the "Remove seats" button exists + await expect(page3.getByTestId("remove-seats-button")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubRemoveTeamMember.spec.js b/docs-tests/tests/dockerHubRemoveTeamMember.spec.js new file mode 100644 index 000000000000..46c8cd6e0d8a --- /dev/null +++ b/docs-tests/tests/dockerHubRemoveTeamMember.spec.js @@ -0,0 +1,44 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#remove-a-member-from-a-team + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubRemoveTeamMember", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Teams + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-teams") + .click(); + + // Select a team + await page2.getByRole("link", { name: "teamteam" }).click(); + + // Verify Remove button exists + await expect(page2.getByLabel("remove team member")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubResendInvitation.spec.js b/docs-tests/tests/dockerHubResendInvitation.spec.js new file mode 100644 index 000000000000..b242a0a41755 --- /dev/null +++ b/docs-tests/tests/dockerHubResendInvitation.spec.js @@ -0,0 +1,49 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#resend-an-invitation + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubResendInvitation", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Members + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-members") + .click(); + + // Select actions menu + await page2 + .getByRole("row", { name: "sarahsanderstestinvite@docker" }) + .getByTestId("member-actions-menu-open") + .click(); + + // Verify Resend invitation button exists + await expect( + page2.getByRole("menuitem", { name: "Resend invitation" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubSSOAddDomain.spec.js b/docs-tests/tests/dockerHubSSOAddDomain.spec.js new file mode 100644 index 000000000000..4afff3d5e8d0 --- /dev/null +++ b/docs-tests/tests/dockerHubSSOAddDomain.spec.js @@ -0,0 +1,45 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/configure/#step-one-add-your-domain + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubSSOAddDomain", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Security + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Security" }).click(); + + // Select Add domain and add your domain + await page2.getByTestId("add-domain").click(); + await page2.getByLabel("Domain", { exact: true }).click(); + await page2 + .getByLabel("Domain", { exact: true }) + .fill("testingtestingtesting.com"); + + // Verify Add domain button exists + await expect(page2.getByTestId("add-domain-button")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubSSOAuditDomains.spec.js b/docs-tests/tests/dockerHubSSOAuditDomains.spec.js new file mode 100644 index 000000000000..35698b6a59ee --- /dev/null +++ b/docs-tests/tests/dockerHubSSOAuditDomains.spec.js @@ -0,0 +1,38 @@ +// This test verifies https://docs.docker.com/security/for-admins/domain-audit/ + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubSSOAuditDomains", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Security + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Security" }).click(); + + // Verify Domain audit section exists + await expect(page2.getByText("Domain AuditVerified domains")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubSSODeleteConnection.spec.js b/docs-tests/tests/dockerHubSSODeleteConnection.spec.js new file mode 100644 index 000000000000..ec65dbda442b --- /dev/null +++ b/docs-tests/tests/dockerHubSSODeleteConnection.spec.js @@ -0,0 +1,45 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/manage/#delete-a-connection + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubSSODeleteConnection", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Security + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Security" }).click(); + + // Select actions menu + await page2 + .getByTestId("sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587") + .click(); + + // Verify Edit connection button exists + await expect( + page2.getByRole("menuitem", { name: "Delete connection" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubSSOEditConnection.spec.js b/docs-tests/tests/dockerHubSSOEditConnection.spec.js new file mode 100644 index 000000000000..333732a1b149 --- /dev/null +++ b/docs-tests/tests/dockerHubSSOEditConnection.spec.js @@ -0,0 +1,46 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/manage/#connect-an-organization +// and https://docs.docker.com/security/for-admins/single-sign-on/manage/#remove-an-organization + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubSSOEditConnection", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Security + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Security" }).click(); + + // Select actions menu + await page2 + .getByTestId("sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587") + .click(); + + // Verify Edit connection button exists + await expect( + page2.getByRole("menuitem", { name: "Edit connection" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubSSOEnableSCIM.spec.js b/docs-tests/tests/dockerHubSSOEnableSCIM.spec.js new file mode 100644 index 000000000000..6dd1b2ed48b3 --- /dev/null +++ b/docs-tests/tests/dockerHubSSOEnableSCIM.spec.js @@ -0,0 +1,45 @@ +// This test verifies https://docs.docker.com/security/for-admins/provisioning/scim/#enable-scim-in-docker + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubSSOEnableSCIM", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Security + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Security" }).click(); + + // Select actions menu + await page2 + .getByTestId("sso-connection-button-bd5e11ac-76b6-43bb-8046-4ef1a01bf587") + .click(); + + // Verify Enable SCIM button exists + await expect( + page2.getByRole("menuitem", { name: "Enable SCIM" }) + ).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubSSORemoveDomain.spec.js b/docs-tests/tests/dockerHubSSORemoveDomain.spec.js new file mode 100644 index 000000000000..ae649135669b --- /dev/null +++ b/docs-tests/tests/dockerHubSSORemoveDomain.spec.js @@ -0,0 +1,38 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/manage/#remove-a-domain-from-an-sso-connection + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubSSORemoveDomain", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Security + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Security" }).click(); + + // Verify Remove domain button exists + await expect(page2.getByLabel("Delete testverifydomain.com")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubSSOVerifyDomain.spec.js b/docs-tests/tests/dockerHubSSOVerifyDomain.spec.js new file mode 100644 index 000000000000..c73a2d999ca3 --- /dev/null +++ b/docs-tests/tests/dockerHubSSOVerifyDomain.spec.js @@ -0,0 +1,41 @@ +// This test verifies https://docs.docker.com/security/for-admins/single-sign-on/configure/#step-two-verify-your-domain + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubSSOVerifyDomain", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Security + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2.getByRole("menuitem", { name: "Security" }).click(); + + // Select Verify domain + await page2.getByRole("button", { name: "Verify", exact: true }).click(); + + // Verify Verify domain button exists + await expect(page2.getByTestId("verify-domain-button")).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubUpdateMemberRole.spec.js b/docs-tests/tests/dockerHubUpdateMemberRole.spec.js new file mode 100644 index 000000000000..93f0f3d89e52 --- /dev/null +++ b/docs-tests/tests/dockerHubUpdateMemberRole.spec.js @@ -0,0 +1,51 @@ +// This test verifies https://docs.docker.com/admin/organization/members/#update-a-member-role + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubUpdateMemberRole", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then members + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-members") + .click(); + + // Select actions menu and Edit role + await page2 + .getByRole("row", { name: "sarahstestaccount Guest sarah" }) + .getByTestId("member-actions-menu-open") + .click(); + await page2.getByRole("menuitem", { name: "Edit role" }).click(); + + // Choose new role + await page2.getByLabel("Full administrative access to").check(); + + // Verify Save button exists + await expect(page2.getByRole("button", { name: "Save" })).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); \ No newline at end of file diff --git a/docs-tests/tests/dockerHubUpgradeSubscription.spec.js b/docs-tests/tests/dockerHubUpgradeSubscription.spec.js new file mode 100644 index 000000000000..6125a4c83811 --- /dev/null +++ b/docs-tests/tests/dockerHubUpgradeSubscription.spec.js @@ -0,0 +1,67 @@ +// This test verifies https://docs.docker.com/subscription/change/#upgrade-your-subscription + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubUpgradeSubscription", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + const hubCard = page.getByTestId("dashboard-card-hub"); + await expect(hubCard).toBeVisible(); + await hubCard.click(); + const page2 = await page2Promise; + await page2.waitForLoadState("load"); + + // Accept Cookies if present on the Docker Hub popup + const acceptCookies = page2.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } + + // Navigate to Billing tab + const billingTab = page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-billing"); + await expect(billingTab).toBeVisible(); + await billingTab.click(); + + // Open Docker Billing page + const page3Promise = page2.waitForEvent("popup"); + const billingLink = page2.getByRole("link", { name: "Docker Billing⁠" }); + await expect(billingLink).toBeVisible(); + await billingLink.click(); + const page3 = await page3Promise; + await page3.waitForLoadState("load"); + + // Ensure the correct organization is selected in Billing + const sidebarBilling = page3.getByTestId("layout-sidebar"); + const contextSwitcherBilling = sidebarBilling.getByLabel( + "open context switcher" + ); + await expect(contextSwitcherBilling).toBeVisible(); + await contextSwitcherBilling.click(); + + const orgBilling = sidebarBilling + .locator("a") + .filter({ hasText: "vrunopayed" }); + await expect(orgBilling).toBeVisible(); + await orgBilling.click(); + + // Wait for the "Upgrade" button to appear + const upgradeButton = page3.getByRole("link", { name: "Upgrade" }); + await expect(upgradeButton).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/dockerHubViewActivityLogs.spec.js b/docs-tests/tests/dockerHubViewActivityLogs.spec.js new file mode 100644 index 000000000000..123210d17967 --- /dev/null +++ b/docs-tests/tests/dockerHubViewActivityLogs.spec.js @@ -0,0 +1,40 @@ +// This test verifies https://docs.docker.com/admin/organization/activity-logs/#view-the-activity-logs + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubViewActivityLogs", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Teams + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + + // Select Activity logs + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-activity") + .click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/dockerHubViewOrganizations.spec.js b/docs-tests/tests/dockerHubViewOrganizations.spec.js new file mode 100644 index 000000000000..ef6cbb12ac1e --- /dev/null +++ b/docs-tests/tests/dockerHubViewOrganizations.spec.js @@ -0,0 +1,33 @@ +// This test verifies https://docs.docker.com/admin/organization/orgs/#view-an-organization + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubViewOrganizations", async ({ page }) => { + // Navigate to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + const hubCard = page.getByTestId("dashboard-card-hub"); + await expect(hubCard).toBeVisible(); + await hubCard.click(); + const page2 = await page2Promise; + await page2.waitForLoadState("load"); + + // Wait for the organization menu item to be visible and click it + await page2.getByTestId('layout-sidebar').getByLabel('open context switcher').click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/dockerHubViewRenewalDate.spec.js b/docs-tests/tests/dockerHubViewRenewalDate.spec.js new file mode 100644 index 000000000000..669e4199219b --- /dev/null +++ b/docs-tests/tests/dockerHubViewRenewalDate.spec.js @@ -0,0 +1,56 @@ +// This test verifies https://docs.docker.com/billing/history/#view-renewal-date + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubViewRenewalDate", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + const hubCard = page.getByTestId("dashboard-card-hub"); + await expect(hubCard).toBeVisible(); + await hubCard.click(); + const page2 = await page2Promise; + await page2.waitForLoadState("load"); + + // Accept cookies if the banner is present + const acceptCookies = page2.getByRole("button", { + name: "Accept All Cookies", + }); + if (await acceptCookies.isVisible({ timeout: 5000 }).catch(() => false)) { + await acceptCookies.click(); + await expect(acceptCookies).toBeHidden(); + } + + // Navigate to Billing tab + const billingTab = page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-billing"); + await expect(billingTab).toBeVisible(); + await billingTab.click(); + + // Open Docker Billing page + const page3Promise = page2.waitForEvent("popup"); + const billingLink = page2.getByRole("link", { name: "Docker Billing⁠" }); + await expect(billingLink).toBeVisible(); + await billingLink.click(); + const page3 = await page3Promise; + await page3.waitForLoadState("load"); + + // Verify the next bill date is visible + const renewalDateLocator = page3 + .locator("div") + .filter({ hasText: /^Next bill/ }) + .getByRole("paragraph"); + await expect(renewalDateLocator).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/dockerHubViewTeamRepoPermissions.spec.js b/docs-tests/tests/dockerHubViewTeamRepoPermissions.spec.js new file mode 100644 index 000000000000..efd60cbb2a0d --- /dev/null +++ b/docs-tests/tests/dockerHubViewTeamRepoPermissions.spec.js @@ -0,0 +1,44 @@ +// This test verifies https://docs.docker.com/admin/organization/manage-a-team/#view-a-teams-permissions-for-all-repositories + +import { test, expect } from "@playwright/test"; +test.use({ storageState: "app-auth.json" }); + +test.beforeEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); + +test("dockerHubViewTeamRepoPermissions", async ({ page }) => { + // Go to Docker Hub + await page.goto("https://app-stage.docker.com/"); + const page2Promise = page.waitForEvent("popup"); + await page.getByTestId("dashboard-card-hub").click(); + const page2 = await page2Promise; + + // Select organizations, your org, then Teams + await page2.getByRole("button", { name: "Accept All Cookies" }).click(); + await page2 + .getByTestId("layout-sidebar") + .getByLabel("open context switcher") + .click(); + await page2 + .getByTestId("layout-sidebar") + .locator("a") + .filter({ hasText: "sarahdatDocker Business" }) + .click(); + await page2 + .getByTestId("layout-sidebar") + .getByTestId("org-page-tab-teams") + .click(); + + // Select a team + await page2.getByRole("link", { name: "teamteam" }).click(); + + // Select Permissions + await page2.getByTestId("permissions").click(); +}); + +test.afterEach(async ({ page }) => { + await page.goto("https://app-stage.docker.com/"); + await page.waitForLoadState("networkidle"); +}); diff --git a/docs-tests/tests/globalSetup.ts b/docs-tests/tests/globalSetup.ts new file mode 100644 index 000000000000..593090adc86e --- /dev/null +++ b/docs-tests/tests/globalSetup.ts @@ -0,0 +1,46 @@ +import { chromium, FullConfig } from '@playwright/test'; +import fs from 'fs'; +import { appLogin } from './loginHelper'; + +async function globalSetup(config: FullConfig) { + const browser = await chromium.launch(); + + console.log("Logging into Docker..."); + const appContext = await browser.newContext({ ignoreHTTPSErrors: true }); + const appPage = await appContext.newPage(); + await appLogin(appPage); + + try { + await appPage.waitForURL('https://app-stage.docker.com/', { timeout: 60000 }); + console.log("App stage found, login confirmed."); + } catch (error) { + console.error("App stage not found. Login may not have completed successfully:", error); + } + + try { + await appPage.goto('https://app-stage.docker.com/', { waitUntil: 'networkidle', timeout: 60000 }); + } catch (error) { + console.error("Error navigating to Docker Home after login:", error); + } + await appPage.waitForLoadState('networkidle'); + + const storageState = await appContext.storageState(); + console.log("Original cookies:", storageState.cookies); + + const updatedCookies = storageState.cookies.map(cookie => { + if (cookie.domain.includes('login-stage.docker.com')) { + console.log(`Updating cookie ${cookie.name} domain from ${cookie.domain} to app-stage.docker.com`); + return { ...cookie, domain: 'app-stage.docker.com' }; + } + return cookie; + }); + const newStorageState = { ...storageState, cookies: updatedCookies }; + + fs.writeFileSync('app-auth.json', JSON.stringify(newStorageState, null, 2)); + console.log("Updated storage state saved to app-auth.json"); + + await appContext.close(); + await browser.close(); +} + +export default globalSetup; \ No newline at end of file diff --git a/docs-tests/tests/loginHelper.ts b/docs-tests/tests/loginHelper.ts new file mode 100644 index 000000000000..b66db792f9cb --- /dev/null +++ b/docs-tests/tests/loginHelper.ts @@ -0,0 +1,19 @@ +import { Page } from '@playwright/test'; + +export async function appLogin(page: Page) { + if (!process.env.ENV_APP_USERNAME || !process.env.ENV_APP_PASSWORD) { + throw new Error("Missing required environment variables: ENV_APP_USERNAME or ENV_APP_PASSWORD"); + } + + await page.goto('https://app-stage.docker.com/'); + await page.getByLabel('Username or email address').waitFor({ timeout: 10000 }); + await page.getByLabel('Username or email address').click(); + await page.getByLabel('Username or email address').fill(process.env.ENV_APP_USERNAME); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + await page.getByRole('link', { name: 'Sign in with Okta FastPass' }).click(); + await page.waitForTimeout(3000); + await page.getByLabel('Password').click(); + await page.getByLabel('Password').fill(process.env.ENV_APP_PASSWORD); + await page.getByRole('button', { name: 'Verify' }).click(); + await page.waitForLoadState('networkidle'); +} \ No newline at end of file