diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 92cd3a6..ceb7e2b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -84,6 +84,32 @@ jobs: - run: HUSKY=0 [ ! -d "./node_modules/" ] && HUSKY=0 yarn install --frozen-lockfile --no-progress - run: yarn workspace api run test:coverage + e2e_test: + runs-on: ubuntu-latest + needs: [prepare] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + - uses: actions/cache@v3 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - run: HUSKY=0 [ ! -d "./node_modules/" ] && HUSKY=0 yarn install --frozen-lockfile --no-progress + - name: Run Playwright tests + run: yarn e2e + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: workspaces/e2e/playwright-report/ + retention-days: 30 + build_image: runs-on: ubuntu-latest needs: [lint, unit_test_frontend, unit_test_backend] diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 45c6daf..c945404 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -80,3 +80,32 @@ jobs: ${{ runner.os }}-yarn- - run: HUSKY=0 [ ! -d "./node_modules/" ] && HUSKY=0 yarn install --frozen-lockfile --no-progress - run: yarn workspace api run test:coverage + + e2e_test: + container: + image: node:lts + options: --user root + runs-on: ubuntu-latest + needs: [prepare] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + - uses: actions/cache@v3 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - run: HUSKY=0 [ ! -d "./node_modules/" ] && HUSKY=0 yarn install --frozen-lockfile --no-progress + - name: Run Playwright tests + run: yarn e2e + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: workspaces/e2e/playwright-report/ + retention-days: 30 diff --git a/workspaces/e2e/package.json b/workspaces/e2e/package.json index a766310..740b990 100644 --- a/workspaces/e2e/package.json +++ b/workspaces/e2e/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "scripts": { - "test": "playwright test --workers=1 --reporter=html", + "test": "playwright test --no-watch --workers=1 --reporter=html", "test:watch": "playwright test --ui --workers=1" }, "devDependencies": { diff --git a/workspaces/e2e/playwright.config.ts b/workspaces/e2e/playwright.config.ts index aaa8286..c17455f 100644 --- a/workspaces/e2e/playwright.config.ts +++ b/workspaces/e2e/playwright.config.ts @@ -1,5 +1,5 @@ import { defineConfig } from "@playwright/test"; export default defineConfig({ - reporter: process.env.CI ? "github" : [["list"], ["html"]], + reporter: process.env.CI ? "github" : [["list"], ["html", { open: "never" }]], }); diff --git a/workspaces/e2e/src/data-presets/data_preset.json b/workspaces/e2e/src/data-presets/data_preset.json index 953e8bc..d90f4a8 100644 --- a/workspaces/e2e/src/data-presets/data_preset.json +++ b/workspaces/e2e/src/data-presets/data_preset.json @@ -1,56 +1,126 @@ { - "markers": { - "a2938f13-28b2-41a0-8e36-f0869b303eea": { - "attributes": {}, - "id": "a2938f13-28b2-41a0-8e36-f0869b303eea", + "locations": { + "78494004-2ac7-45c5-97ff-9a054aa906f2": { + "id": "78494004-2ac7-45c5-97ff-9a054aa906f2", + "image": "", "name": "2nd floor", - "lat": 397, - "lng": 622, - "type": "room", - "icon": "bookable", - "rotation": 0 + "shortName": "2", + "description": "", + "markers": { + "a2938f13-28b2-41a0-8e36-f0869b303eea": { + "attributes": {}, + "id": "a2938f13-28b2-41a0-8e36-f0869b303eea", + "name": "2nd floor", + "lat": 397, + "lng": 622, + "type": "room", + "icon": "bookable", + "rotation": 0 + } + } }, - "79f7a4f2-2c4e-4c8f-a9d3-d90d6a0b8995": { - "attributes": {}, - "id": "79f7a4f2-2c4e-4c8f-a9d3-d90d6a0b8995", - "name": "Jennifer Jarsen", - "image": "588f17c4-5980-41e1-85ad-38940671ceb1", - "lat": 905, - "lng": 742, - "type": "person", - "icon": "person", - "rotation": 0 + "979f806c-297a-4c99-88db-2363a34dba38": { + "markers": { + "79f7a4f2-2c4e-4c8f-a9d3-d90d6a0b8995": { + "attributes": {}, + "id": "79f7a4f2-2c4e-4c8f-a9d3-d90d6a0b8995", + "name": "Jennifer Jarsen", + "image": "588f17c4-5980-41e1-85ad-38940671ceb1", + "lat": 905, + "lng": 742, + "type": "person", + "icon": "person", + "rotation": 0 + }, + "8f17c459-8001-4185-ad38-940671ceb190": { + "attributes": {}, + "id": "8f17c459-8001-4185-ad38-940671ceb190", + "name": "[New Table]", + "lat": 924, + "lng": 770, + "type": "table", + "icon": "table", + "rotation": 0 + } + }, + "id": "979f806c-297a-4c99-88db-2363a34dba38", + "name": "1st floor", + "shortName": "1", + "image": "" }, - "8f17c459-8001-4185-ad38-940671ceb190": { - "attributes": {}, - "id": "8f17c459-8001-4185-ad38-940671ceb190", - "name": "[New Table]", - "lat": 924, - "lng": 770, - "type": "table", - "icon": "table", - "rotation": 0 - }, - "d01e096f-dd0b-4f49-943c-1b4e50133501": { - "attributes": {}, - "id": "d01e096f-dd0b-4f49-943c-1b4e50133501", - "name": "John Doe", - "lat": 649, - "lng": 26, - "type": "person", - "icon": "person", - "rotation": 0 - }, - "1e096fdd-0b2f-4994-bc1b-4e50133501d1": { - "attributes": {}, - "id": "1e096fdd-0b2f-4994-bc1b-4e50133501d1", - "name": "First aid kit", - "lat": 7, - "lng": 18, - "type": "emergency", - "icon": "firstaidkit", - "rotation": 0 + "9a6494b1-be0b-4e36-aad2-fb6588171632": { + "markers": { + "d01e096f-dd0b-4f49-943c-1b4e50133501": { + "attributes": { + "Post": "Receptionist" + }, + "id": "d01e096f-dd0b-4f49-943c-1b4e50133501", + "name": "John Doe", + "lat": 665, + "lng": 232, + "type": "person", + "icon": "person", + "rotation": 180 + }, + "1e096fdd-0b2f-4994-bc1b-4e50133501d1": { + "attributes": {}, + "id": "1e096fdd-0b2f-4994-bc1b-4e50133501d1", + "name": "First aid kit", + "lat": 71, + "lng": 74, + "type": "emergency", + "icon": "firstaidkit", + "rotation": 0 + }, + "f7122fa1-96ed-49d8-84a2-2bd4a7c41d85": { + "attributes": {}, + "id": "f7122fa1-96ed-49d8-84a2-2bd4a7c41d85", + "name": "Printer", + "lat": 942, + "lng": 892, + "type": "other", + "icon": "printer", + "rotation": 0 + }, + "122fa196-ede9-4844-a22b-d4a7c41d854f": { + "attributes": {}, + "id": "122fa196-ede9-4844-a22b-d4a7c41d854f", + "name": "[New Toilet]", + "lat": 855, + "lng": 1128, + "type": "toilet", + "icon": "ladies", + "rotation": 0 + }, + "2fa196ed-e9d8-44a2-abd4-a7c41d854f17": { + "attributes": {}, + "id": "2fa196ed-e9d8-44a2-abd4-a7c41d854f17", + "name": "[New Toilet]", + "lat": 601, + "lng": 1126, + "type": "toilet", + "icon": "gentlemens", + "rotation": 0 + }, + "a196ede9-d844-422b-94a7-c41d854f17c5": { + "attributes": {}, + "id": "a196ede9-d844-422b-94a7-c41d854f17c5", + "name": "[New Table]", + "lat": 644, + "lng": 262, + "type": "table", + "icon": "table", + "rotation": 0 + } + }, + "id": "9a6494b1-be0b-4e36-aad2-fb6588171632", + "name": "Ground", + "shortName": "G", + "image": "75f7122f-a196-4de9-9844-a22bd4a7c41d", + "description": "Das ist 2 Test", + "width": 1300, + "height": 1000 } }, - "version": 2 + "version": 3 } \ No newline at end of file diff --git a/workspaces/e2e/src/data-presets/images/75f7122f-a196-4de9-9844-a22bd4a7c41d b/workspaces/e2e/src/data-presets/images/75f7122f-a196-4de9-9844-a22bd4a7c41d new file mode 100644 index 0000000..22f5907 Binary files /dev/null and b/workspaces/e2e/src/data-presets/images/75f7122f-a196-4de9-9844-a22bd4a7c41d differ diff --git a/workspaces/e2e/src/pages/Map.ts b/workspaces/e2e/src/pages/Map.ts index 41b1055..cf5f371 100644 --- a/workspaces/e2e/src/pages/Map.ts +++ b/workspaces/e2e/src/pages/Map.ts @@ -9,10 +9,6 @@ export class Map { this.locator = locator; } - async isVisible(): Promise { - return await this.locator.isVisible(); - } - markers(): Locator { return this.locator.locator(".leaflet-layer"); } diff --git a/workspaces/e2e/src/pages/NavigationBar.ts b/workspaces/e2e/src/pages/NavigationBar.ts new file mode 100644 index 0000000..348307b --- /dev/null +++ b/workspaces/e2e/src/pages/NavigationBar.ts @@ -0,0 +1,27 @@ +import { Locator, Page } from "@playwright/test"; + +export class NavigationBar { + readonly page: Page; + readonly locator: Locator; + + constructor(page: Page, locator: Locator) { + this.page = page; + this.locator = locator; + } + + locations(): Locator { + return this.locator.getByTestId("nav-locations").locator(".nav-item"); + } + + activeLocation(): Promise { + return this.locator + .getByTestId("nav-locations") + .locator(".nav-item--active") + .getByTestId("nav-item-title") + .textContent(); + } + + markerTypes(): Locator { + return this.locator.getByTestId("nav-markerTypes").locator(".nav-item"); + } +} diff --git a/workspaces/e2e/src/pages/StartPage.ts b/workspaces/e2e/src/pages/StartPage.ts index a7975b5..832eb78 100644 --- a/workspaces/e2e/src/pages/StartPage.ts +++ b/workspaces/e2e/src/pages/StartPage.ts @@ -1,5 +1,6 @@ import { Locator, Page } from "@playwright/test"; import { Map } from "./Map"; +import { NavigationBar } from "./NavigationBar"; export class StartPage { readonly page: Page; @@ -20,8 +21,8 @@ export class StartPage { await this.page.goto(`http://localhost:${process.env.APP_PORT}`); } - getNavigationBar(): Locator { - return this.navigationBar; + getNavigationBar(): NavigationBar { + return new NavigationBar(this.page, this.navigationBar); } getMap(): Map { diff --git a/workspaces/e2e/src/tests/application.test.ts b/workspaces/e2e/src/tests/application.test.ts index e261119..2d1c32c 100644 --- a/workspaces/e2e/src/tests/application.test.ts +++ b/workspaces/e2e/src/tests/application.test.ts @@ -3,35 +3,96 @@ import { StartPage } from "../pages/StartPage"; test.describe("Application", async () => { test("should be visible with some markers", async ({ startPage }) => { - await expect(startPage.getNavigationBar()).toBeVisible(); - expect(await startPage.getMap().isVisible()).toBe(true); - + // check map + await expect(startPage.map).toBeVisible(); await startPage.getMap().markers().first().waitFor(); - await expect(await startPage.getMap().markers()).toHaveCount(5); + await expect(await startPage.getMap().markers()).toHaveCount(1); + + // check navigation + await expect(startPage.navigationBar).toBeVisible(); + expect(await startPage.getNavigationBar().activeLocation()).toEqual( + "2nd floor" + ); + await Promise.all( + [ + "Table 0", + "Person 0", + "Room 1", + "Toilet 0", + "Emergency 0", + "Other 0", + ].map((markerType) => { + expect( + startPage.getNavigationBar().markerTypes().getByText(markerType) + ).toBeVisible(); + }) + ); }); - test("should load a specific marker", async ({ page }) => { + test("should load a specific location and marker", async ({ page }) => { await page.goto( - `http://localhost:${process.env.APP_PORT}/#/markers/d01e096f-dd0b-4f49-943c-1b4e50133501` + `http://localhost:${process.env.APP_PORT}/#/locations/9a6494b1-be0b-4e36-aad2-fb6588171632/markers/d01e096f-dd0b-4f49-943c-1b4e50133501` ); const startPage = new StartPage(page); + // check map await startPage.getMap().markers().first().waitFor(); const map = startPage.getMap(); + await expect(await startPage.getMap().markers()).toHaveCount(6); await expect(map.markerWithTooltip("John Doe")).toBeInViewport(); await expect(map.markerWithTooltip("Jennifer Jarsen")).not.toBeInViewport(); + + // check navigation + await expect(startPage.navigationBar).toBeVisible(); + expect(await startPage.getNavigationBar().activeLocation()).toEqual( + "Ground" + ); + await Promise.all( + [ + "Table 1", + "Person 1", + "Room 0", + "Toilet 2", + "Emergency 1", + "Other 1", + ].map((markerType) => { + expect( + startPage.getNavigationBar().markerTypes().getByText(markerType) + ).toBeVisible(); + }) + ); }); test("should load a specific position in map", async ({ page }) => { await page.goto( - `http://localhost:${process.env.APP_PORT}/#/coords/615.5/1065/0` + `http://localhost:${process.env.APP_PORT}/#/locations/979f806c-297a-4c99-88db-2363a34dba38/coords/615.5/1065/0` ); const startPage = new StartPage(page); await startPage.getMap().markers().first().waitFor(); const map = startPage.getMap(); + await expect(await startPage.getMap().markers()).toHaveCount(2); await expect(map.markerWithTooltip("John Doe")).not.toBeInViewport(); await expect(map.markerWithTooltip("Jennifer Jarsen")).toBeInViewport(); - await expect(map.markerWithTooltip("2nd floor")).toBeInViewport(); + + // check navigation + await expect(startPage.navigationBar).toBeVisible(); + expect(await startPage.getNavigationBar().activeLocation()).toEqual( + "1st floor" + ); + await Promise.all( + [ + "Table 1", + "Person 1", + "Room 0", + "Toilet 0", + "Emergency 0", + "Other 0", + ].map((markerType) => { + expect( + startPage.getNavigationBar().markerTypes().getByText(markerType) + ).toBeVisible(); + }) + ); }); }); diff --git a/workspaces/frontend/src/components/NavigationItem.svelte b/workspaces/frontend/src/components/NavigationItem.svelte index b7a1f17..46dbd2c 100644 --- a/workspaces/frontend/src/components/NavigationItem.svelte +++ b/workspaces/frontend/src/components/NavigationItem.svelte @@ -16,10 +16,10 @@ type="button" class="w-full text-left hover:text-black" on:click={toggleVisibility}> - + - + {#if counter !== undefined} diff --git a/workspaces/frontend/src/components/NavigationSideBar.svelte b/workspaces/frontend/src/components/NavigationSideBar.svelte index e88cb75..b3e39cd 100644 --- a/workspaces/frontend/src/components/NavigationSideBar.svelte +++ b/workspaces/frontend/src/components/NavigationSideBar.svelte @@ -92,7 +92,7 @@ -