chore(e2e): updates testing to use playwright (#2181)
* chore(e2e): updates testing to use playwright * chore: updates workflows * fixes spaces * fixes space again * fixes int test to add docker * chore: ignore e2e tests for vite * updates screenshots for linux * updates screenshots again * chore: uses docker compose for e2e * adds PWTEST_SKIP_TEST_OUTPUT * add ci * updates screenshots again * updates with css * adds more tests * updates tests
28
.github/workflows/test.yml
vendored
@@ -61,19 +61,37 @@ jobs:
|
|||||||
run: make test SKIP_ASSET=1
|
run: make test SKIP_ASSET=1
|
||||||
int-test:
|
int-test:
|
||||||
name: Integration Tests
|
name: Integration Tests
|
||||||
|
timeout-minutes: 60
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- uses: actions/checkout@v3
|
||||||
uses: actions/checkout@v3
|
- uses: actions/setup-node@v3
|
||||||
|
name: Install Node
|
||||||
|
with:
|
||||||
|
node-version: latest
|
||||||
|
- run: corepack enable
|
||||||
|
- run: pnpm --version
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: latest
|
||||||
|
cache: "pnpm"
|
||||||
|
cache-dependency-path: "**/pnpm-lock.yaml"
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: docker/bake-action@v3
|
uses: docker/bake-action@v3
|
||||||
with:
|
with:
|
||||||
workdir: ./e2e
|
|
||||||
load: true
|
load: true
|
||||||
set: |
|
set: |
|
||||||
*.cache-from=type=gha
|
*.cache-from=type=gha
|
||||||
*.cache-to=type=gha,mode=max
|
*.cache-to=type=gha,mode=max
|
||||||
- name: Run tests
|
- name: Run Playwright tests
|
||||||
run: docker compose -f e2e/docker-compose.yml up --exit-code-from cypress
|
run: docker compose up --exit-code-from playwright
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: playwright-report
|
||||||
|
path: playwright-report/
|
||||||
|
retention-days: 30
|
||||||
|
|||||||
3
.gitignore
vendored
@@ -9,3 +9,6 @@ coverage
|
|||||||
.vscode
|
.vscode
|
||||||
coverage.out
|
coverage.out
|
||||||
.netlify
|
.netlify
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
|||||||
2
Makefile
@@ -31,4 +31,4 @@ dev:
|
|||||||
|
|
||||||
.PHONY: int
|
.PHONY: int
|
||||||
int:
|
int:
|
||||||
docker-compose -f e2e/docker-compose.yml up --build --force-recreate --exit-code-from cypress
|
docker compose up --force-recreate --exit-code-from playwright
|
||||||
|
|||||||
999
assets/auto-imports.d.ts
vendored
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<time :datetime="date.toISOString()">{{ text }}</time>
|
<time :datetime="date.toISOString()" data-ci-skip>{{ text }}</time>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|||||||
@@ -40,7 +40,12 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-narrow py-0" :class="secured ? 'pl-0 pr-1' : 'px-0'">
|
<div class="column is-narrow py-0" :class="secured ? 'pl-0 pr-1' : 'px-0'">
|
||||||
<router-link :to="{ name: 'settings' }" active-class="is-active" class="button is-rounded is-small">
|
<router-link
|
||||||
|
:to="{ name: 'settings' }"
|
||||||
|
active-class="is-active"
|
||||||
|
class="button is-rounded is-small"
|
||||||
|
:aria-label="$t('title.settings')"
|
||||||
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<mdi:light-cog />
|
<mdi:light-cog />
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -13,15 +13,15 @@
|
|||||||
<p class="heading">{{ $t("label.running") }}</p>
|
<p class="heading">{{ $t("label.running") }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="level-item has-text-centered">
|
<div class="level-item has-text-centered" data-ci-skip>
|
||||||
<div>
|
<div>
|
||||||
<p class="title" data-ci-skip>{{ totalCpu }}%</p>
|
<p class="title">{{ totalCpu }}%</p>
|
||||||
<p class="heading">{{ $t("label.total-cpu-usage") }}</p>
|
<p class="heading">{{ $t("label.total-cpu-usage") }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="level-item has-text-centered">
|
<div class="level-item has-text-centered" data-ci-skip>
|
||||||
<div>
|
<div>
|
||||||
<p class="title" data-ci-skip>{{ formatBytes(totalMem) }}</p>
|
<p class="title">{{ formatBytes(totalMem) }}</p>
|
||||||
<p class="heading">{{ $t("label.total-mem-usage") }}</p>
|
<p class="heading">{{ $t("label.total-mem-usage") }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
52
docker-compose.yml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
version: "3.4"
|
||||||
|
services:
|
||||||
|
custom_base:
|
||||||
|
container_name: custom_base
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
environment:
|
||||||
|
- DOZZLE_FILTER=name=custom_base
|
||||||
|
- DOZZLE_BASE=/foobarbase
|
||||||
|
- DOZZLE_NO_ANALYTICS=1
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
auth:
|
||||||
|
container_name: auth
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
environment:
|
||||||
|
- DOZZLE_FILTER=name=auth
|
||||||
|
- DOZZLE_USERNAME=foo
|
||||||
|
- DOZZLE_PASSWORD=bar
|
||||||
|
- DOZZLE_NO_ANALYTICS=1
|
||||||
|
ports:
|
||||||
|
- 9090:8080
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dozzle:
|
||||||
|
container_name: dozzle
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
environment:
|
||||||
|
- DOZZLE_FILTER=name=dozzle
|
||||||
|
- DOZZLE_NO_ANALYTICS=1
|
||||||
|
ports:
|
||||||
|
- 7070:8080
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
playwright:
|
||||||
|
container_name: playwright
|
||||||
|
image: mcr.microsoft.com/playwright:v1.33.0-jammy
|
||||||
|
working_dir: /app
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
command: npx --yes playwright test
|
||||||
|
environment:
|
||||||
|
- PWTEST_SKIP_TEST_OUTPUT=1
|
||||||
|
- CI=1
|
||||||
|
depends_on:
|
||||||
|
- dozzle
|
||||||
|
- custom_base
|
||||||
|
- auth
|
||||||
3
e2e/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
videos
|
|
||||||
screenshots
|
|
||||||
__diff_output__
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
FROM cypress/included:12.12.0
|
|
||||||
|
|
||||||
RUN npm i -g pnpm
|
|
||||||
|
|
||||||
WORKDIR /e2e
|
|
||||||
|
|
||||||
COPY pnpm-lock.yaml ./
|
|
||||||
RUN pnpm fetch
|
|
||||||
|
|
||||||
COPY package.json tsconfig.json ./
|
|
||||||
RUN pnpm install --offline
|
|
||||||
9
e2e/auth.spec.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
|
||||||
|
test("authentication", async ({ page }) => {
|
||||||
|
await page.goto("http://auth:8080/");
|
||||||
|
await page.locator('input[name="username"]').fill("foo");
|
||||||
|
await page.locator('input[name="password"]').fill("bar");
|
||||||
|
await page.getByRole("button", { name: "Login" }).click();
|
||||||
|
await expect(page.locator("p.menu-label")).toHaveText("Containers");
|
||||||
|
});
|
||||||
13
e2e/custom.spec.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto("http://custom_base:8080/foobarbase");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("has right title", async ({ page }) => {
|
||||||
|
await expect(page).toHaveTitle(/.* - Dozzle/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("url should have custom base", async ({ page }) => {
|
||||||
|
await expect(page).toHaveURL(/foobarbase/);
|
||||||
|
});
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { defineConfig } from "cypress";
|
|
||||||
import { initPlugin } from "@frsource/cypress-plugin-visual-regression-diff/dist/plugins";
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
fixturesFolder: false,
|
|
||||||
projectId: "8cua4m",
|
|
||||||
|
|
||||||
e2e: {
|
|
||||||
setupNodeEvents(on, config) {
|
|
||||||
initPlugin(on, config);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"DOZZLE_DEFAULT": "http://localhost:8080/",
|
|
||||||
"DOZZLE_AUTH": "http://localhost:8080/"
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 34 KiB |
@@ -1,14 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
context("Dozzle default mode", { baseUrl: Cypress.env("DOZZLE_AUTH") }, () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.visit("/");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("login screen", () => {
|
|
||||||
cy.get("input[name=username]").type("foo");
|
|
||||||
cy.get("input[name=password]").type("bar");
|
|
||||||
cy.get("button[type=submit]").click();
|
|
||||||
cy.get("p.menu-label").should("contain", "Containers");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
context("Dozzle default mode", { baseUrl: Cypress.env("DOZZLE_DEFAULT") }, () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.visit("/");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("home screen", () => {
|
|
||||||
cy.get("li.running", { timeout: 10000 }).removeDates().replaceSkippedElements().matchImage();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("correct title is shown", () => {
|
|
||||||
cy.title().should("eq", "1 containers - Dozzle");
|
|
||||||
|
|
||||||
cy.get("li.running:first a").click();
|
|
||||||
|
|
||||||
cy.title().should("include", "- Dozzle");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("navigating to setting page works ", () => {
|
|
||||||
cy.get("a[href='/settings']").click();
|
|
||||||
|
|
||||||
cy.contains("About");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shortcut for fuzzy search works", () => {
|
|
||||||
cy.get("body").type("{ctrl}k");
|
|
||||||
|
|
||||||
cy.get("input[placeholder='Search containers (⌘ + k, ⌃k)']").should("be.visible");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
context("Dozzle es lang", { baseUrl: Cypress.env("DOZZLE_DEFAULT") }, () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.visit("/", {
|
|
||||||
onBeforeLoad(win) {
|
|
||||||
Object.defineProperty(win.navigator, "language", {
|
|
||||||
value: "es_MX",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should find contenedores", () => {
|
|
||||||
cy.get("p.menu-label").should("contain", "Contenedores");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
context("Dozzle settings mode", { baseUrl: Cypress.env("DOZZLE_DEFAULT") }, () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.visit("/version").clearLocalStorage().visit("/settings");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("scrollbars", () => {
|
|
||||||
cy.contains("Use smaller scrollbars").click();
|
|
||||||
cy.get("html").should("have.class", "has-custom-scrollbars");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("stopped containers", () => {
|
|
||||||
cy.contains("Show stopped containers")
|
|
||||||
.click()
|
|
||||||
.then(() => {
|
|
||||||
expect(JSON.parse(localStorage.getItem("DOZZLE_SETTINGS")).showAllContainers).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
context("Dozzle custom base", { baseUrl: Cypress.env("DOZZLE_CUSTOM") }, () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.visit("/");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("custom base should work", () => {
|
|
||||||
cy.get("p.menu-label").should("contain", "Containers");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("url should be custom", () => {
|
|
||||||
cy.url().should("include", "foobarbase");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
context("Dozzle dark mode", { baseUrl: Cypress.env("DOZZLE_DEFAULT") }, () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.visit("/");
|
|
||||||
cy.window().then((win) => win.document.documentElement.setAttribute("data-theme", "dark"));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("home screen", () => {
|
|
||||||
cy.get("li.running", { timeout: 10000 }).removeDates().replaceSkippedElements().matchImage();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
context("Dozzle routes", { baseUrl: Cypress.env("DOZZLE_DEFAULT") }, () => {
|
|
||||||
it("show", () => {
|
|
||||||
cy.visit("/show?name=dozzle").url().should("include", "/container/");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Using fixtures to represent data",
|
|
||||||
"email": "hello@cypress.io",
|
|
||||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,45 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
// ***********************************************
|
|
||||||
// This example commands.ts shows you how to
|
|
||||||
// create various custom commands and overwrite
|
|
||||||
// existing commands.
|
|
||||||
//
|
|
||||||
// For more comprehensive examples of custom
|
|
||||||
// commands please read more here:
|
|
||||||
// https://on.cypress.io/custom-commands
|
|
||||||
// ***********************************************
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a parent command --
|
|
||||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a child command --
|
|
||||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a dual command --
|
|
||||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This will overwrite an existing command --
|
|
||||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
|
||||||
//
|
|
||||||
// declare global {
|
|
||||||
// namespace Cypress {
|
|
||||||
// interface Chainable {
|
|
||||||
// login(email: string, password: string): Chainable<void>
|
|
||||||
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
|
||||||
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
|
||||||
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
Cypress.Commands.add("removeDates", () => {
|
|
||||||
cy.window().then((win) => win.document.querySelectorAll("time").forEach((el) => el.remove()));
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add("replaceSkippedElements", () => {
|
|
||||||
cy.window().then((win) => win.document.querySelectorAll("[data-ci-skip]").forEach((el) => el.remove()));
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// ***********************************************************
|
|
||||||
// This example support/e2e.ts is processed and
|
|
||||||
// loaded automatically before your test files.
|
|
||||||
//
|
|
||||||
// This is a great place to put global configuration and
|
|
||||||
// behavior that modifies Cypress.
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off
|
|
||||||
// automatically serving support files with the
|
|
||||||
// 'supportFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/configuration
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// Import commands.js using ES2015 syntax:
|
|
||||||
import "./commands";
|
|
||||||
import "@frsource/cypress-plugin-visual-regression-diff/dist/support";
|
|
||||||
|
|
||||||
// Alternatively you can use CommonJS syntax:
|
|
||||||
// require('./commands')
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"noEmit": true,
|
|
||||||
// be explicit about types included
|
|
||||||
// to avoid clashing with Jest types
|
|
||||||
"types": ["cypress"]
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"../node_modules/cypress",
|
|
||||||
"./**/*.ts",
|
|
||||||
"./**/*.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
32
e2e/default.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto("http://dozzle:8080/");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("has right title", async ({ page }) => {
|
||||||
|
await expect(page).toHaveTitle(/.* - Dozzle/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("click on settings button", async ({ page }) => {
|
||||||
|
await page.getByRole("link", { name: "Settings" }).click();
|
||||||
|
await expect(page.getByRole("heading", { name: "About" })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("shortcut for fuzzy search", async ({ page }) => {
|
||||||
|
await page.locator("body").press("Control+k");
|
||||||
|
await expect(page.locator(".modal").getByPlaceholder("Search containers (⌘ + k, ⌃k)")).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("route by name", async ({ page }) => {
|
||||||
|
await page.goto("http://dozzle:8080/show?name=dozzle");
|
||||||
|
await expect(page).toHaveURL(/\/container/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe("es locale", () => {
|
||||||
|
test.use({ locale: "es" });
|
||||||
|
|
||||||
|
test("translated text", async ({ page }) => {
|
||||||
|
await expect(page.locator("p.menu-label").getByText("Contenedores")).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
version: "3.4"
|
|
||||||
services:
|
|
||||||
custom_base:
|
|
||||||
container_name: custom_base
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
environment:
|
|
||||||
- DOZZLE_FILTER=name=custom_base
|
|
||||||
- DOZZLE_BASE=/foobarbase
|
|
||||||
- DOZZLE_NO_ANALYTICS=1
|
|
||||||
image: amir20/dozzle_custom_cache
|
|
||||||
build:
|
|
||||||
context: ..
|
|
||||||
cache_from:
|
|
||||||
- amir20/dozzle_custom_cache:latest
|
|
||||||
auth:
|
|
||||||
container_name: auth
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
environment:
|
|
||||||
- DOZZLE_FILTER=name=auth
|
|
||||||
- DOZZLE_USERNAME=foo
|
|
||||||
- DOZZLE_PASSWORD=bar
|
|
||||||
- DOZZLE_NO_ANALYTICS=1
|
|
||||||
image: amir20/dozzle_custom_cache
|
|
||||||
build:
|
|
||||||
context: ..
|
|
||||||
cache_from:
|
|
||||||
- amir20/dozzle_custom_cache:latest
|
|
||||||
dozzle:
|
|
||||||
container_name: dozzle
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
environment:
|
|
||||||
- DOZZLE_FILTER=name=dozzle
|
|
||||||
- DOZZLE_NO_ANALYTICS=1
|
|
||||||
image: amir20/dozzle_cache:latest
|
|
||||||
build:
|
|
||||||
context: ..
|
|
||||||
cache_from:
|
|
||||||
- amir20/dozzle_cache:latest
|
|
||||||
cypress:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
cache_from:
|
|
||||||
- amir20/dozzle_cypress_cache:latest
|
|
||||||
image: amir20/dozzle_cypress_cache:latest
|
|
||||||
working_dir: /e2e
|
|
||||||
volumes:
|
|
||||||
- ./cypress:/e2e/cypress
|
|
||||||
- ./cypress.config.ts:/e2e/cypress.config.ts
|
|
||||||
environment:
|
|
||||||
- CYPRESS_DOZZLE_DEFAULT=http://dozzle:8080/
|
|
||||||
- CYPRESS_DOZZLE_AUTH=http://auth:8080/
|
|
||||||
- CYPRESS_DOZZLE_CUSTOM=http://custom_base:8080/foobarbase
|
|
||||||
- CYPRESS_RECORD_KEY=155c3cf8-b2dd-4f5e-9fb3-7635f5b79d4d
|
|
||||||
- COMMIT_INFO_BRANCH=${GITHUB_REF_NAME}
|
|
||||||
- COMMIT_INFO_AUTHOR=${GITHUB_ACTOR}
|
|
||||||
- COMMIT_INFO_SHA=${GITHUB_SHA}
|
|
||||||
- COMMIT_INFO_MESSAGE=${GIT_LOG_MESSAGE}
|
|
||||||
- COMMIT_INFO_REMOTE=https://github.com/amir20/dozzle
|
|
||||||
command: cypress run --record
|
|
||||||
depends_on:
|
|
||||||
- dozzle
|
|
||||||
- custom_base
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "e2e",
|
|
||||||
"scripts": {
|
|
||||||
"test": "cypress run"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@frsource/cypress-plugin-visual-regression-diff": "^3.3.0",
|
|
||||||
"cypress": "^12.12.0",
|
|
||||||
"typescript": "^5.0.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1414
e2e/pnpm-lock.yaml
generated
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"lib": ["es5", "dom"],
|
|
||||||
"types": ["cypress", "node"]
|
|
||||||
},
|
|
||||||
"include": ["**/*.ts"]
|
|
||||||
}
|
|
||||||
20
e2e/visual.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto("http://dozzle:8080/");
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe("default", () => {
|
||||||
|
test("homepage", async ({ page }) => {
|
||||||
|
await page.addStyleTag({ content: `[data-ci-skip] { visibility: hidden; }` });
|
||||||
|
await expect(page).toHaveScreenshot({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe("dark", () => {
|
||||||
|
test.use({ colorScheme: "dark" });
|
||||||
|
test("homepage", async ({ page }) => {
|
||||||
|
await page.addStyleTag({ content: `[data-ci-skip] { visibility: hidden; }` });
|
||||||
|
await expect(page).toHaveScreenshot({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 17 KiB |
BIN
e2e/visual.spec.ts-snapshots/dark-homepage-1-chromium-linux.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
e2e/visual.spec.ts-snapshots/dark-homepage-1-webkit-linux.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 29 KiB |
BIN
e2e/visual.spec.ts-snapshots/default-homepage-1-webkit-linux.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
@@ -57,6 +57,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@pinia/testing": "^0.1.2",
|
"@pinia/testing": "^0.1.2",
|
||||||
|
"@playwright/test": "^1.33.0",
|
||||||
"@types/d3-array": "^3.0.4",
|
"@types/d3-array": "^3.0.4",
|
||||||
"@types/d3-ease": "^3.0.0",
|
"@types/d3-ease": "^3.0.0",
|
||||||
"@types/d3-scale": "^4.0.3",
|
"@types/d3-scale": "^4.0.3",
|
||||||
|
|||||||
71
playwright.config.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { defineConfig, devices } from "@playwright/test";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read environment variables from file.
|
||||||
|
* https://github.com/motdotla/dotenv
|
||||||
|
*/
|
||||||
|
// require('dotenv').config();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: "./e2e",
|
||||||
|
/* Run tests in files in parallel */
|
||||||
|
fullyParallel: true,
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
/* Retry on CI only */
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: "html",
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
// baseURL: 'http://127.0.0.1:3000',
|
||||||
|
|
||||||
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
|
trace: "on-first-retry",
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: "chromium",
|
||||||
|
use: { ...devices["Desktop Chrome"] },
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "webkit",
|
||||||
|
use: { ...devices["Desktop Safari"] },
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "Mobile Chrome",
|
||||||
|
use: { ...devices["Pixel 5"] },
|
||||||
|
testMatch: "**/visual.spec.ts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Mobile Safari",
|
||||||
|
use: { ...devices["iPhone 12"] },
|
||||||
|
testMatch: "**/visual.spec.ts",
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Test against branded browsers. */
|
||||||
|
// {
|
||||||
|
// name: 'Microsoft Edge',
|
||||||
|
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Google Chrome',
|
||||||
|
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
// webServer: {
|
||||||
|
// command: "docker compose up",
|
||||||
|
// url: "http://127.0.0.1:7070",
|
||||||
|
// reuseExistingServer: !process.env.CI,
|
||||||
|
// },
|
||||||
|
});
|
||||||
20
pnpm-lock.yaml
generated
@@ -90,6 +90,9 @@ devDependencies:
|
|||||||
'@pinia/testing':
|
'@pinia/testing':
|
||||||
specifier: ^0.1.2
|
specifier: ^0.1.2
|
||||||
version: 0.1.2(pinia@2.1.3)(vue@3.3.4)
|
version: 0.1.2(pinia@2.1.3)(vue@3.3.4)
|
||||||
|
'@playwright/test':
|
||||||
|
specifier: ^1.33.0
|
||||||
|
version: 1.33.0
|
||||||
'@types/d3-array':
|
'@types/d3-array':
|
||||||
specifier: ^3.0.4
|
specifier: ^3.0.4
|
||||||
version: 3.0.4
|
version: 3.0.4
|
||||||
@@ -868,6 +871,17 @@ packages:
|
|||||||
- vue
|
- vue
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@playwright/test@1.33.0:
|
||||||
|
resolution: {integrity: sha512-YunBa2mE7Hq4CfPkGzQRK916a4tuZoVx/EpLjeWlTVOnD4S2+fdaQZE0LJkbfhN5FTSKNLdcl7MoT5XB37bTkg==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.2.1
|
||||||
|
playwright-core: 1.33.0
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@rollup/pluginutils@5.0.2:
|
/@rollup/pluginutils@5.0.2:
|
||||||
resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==}
|
resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@@ -3430,6 +3444,12 @@ packages:
|
|||||||
pathe: 1.1.0
|
pathe: 1.1.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/playwright-core@1.33.0:
|
||||||
|
resolution: {integrity: sha512-aizyPE1Cj62vAECdph1iaMILpT0WUDCq3E6rW6I+dleSbBoGbktvJtzS6VHkZ4DKNEOG9qJpiom/ZxO+S15LAw==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/postcss@8.4.23:
|
/postcss@8.4.23:
|
||||||
resolution: {integrity: sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==}
|
resolution: {integrity: sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import IconsResolver from "unplugin-icons/resolver";
|
|||||||
import Pages from "vite-plugin-pages";
|
import Pages from "vite-plugin-pages";
|
||||||
import Layouts from "vite-plugin-vue-layouts";
|
import Layouts from "vite-plugin-vue-layouts";
|
||||||
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
|
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
|
||||||
import basicSsl from '@vitejs/plugin-basic-ssl'
|
import basicSsl from "@vitejs/plugin-basic-ssl";
|
||||||
|
|
||||||
|
|
||||||
export default defineConfig(() => ({
|
export default defineConfig(() => ({
|
||||||
resolve: {
|
resolve: {
|
||||||
@@ -66,7 +65,7 @@ export default defineConfig(() => ({
|
|||||||
strictMessage: false,
|
strictMessage: false,
|
||||||
include: [path.resolve(__dirname, "locales/**")],
|
include: [path.resolve(__dirname, "locales/**")],
|
||||||
}),
|
}),
|
||||||
basicSsl()
|
basicSsl(),
|
||||||
],
|
],
|
||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: {
|
||||||
@@ -79,4 +78,7 @@ export default defineConfig(() => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
test: {
|
||||||
|
include: ["assets/**/*.spec.ts"],
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||