diff --git a/.github/workflows/clean_tree.yaml b/.github/workflows/clean_tree.yaml deleted file mode 100644 index a7278ec5..00000000 --- a/.github/workflows/clean_tree.yaml +++ /dev/null @@ -1,38 +0,0 @@ -name: Test Clean Tree -on: - pull_request: -jobs: - git-clean-tree-test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Run install - uses: borales/actions-yarn@v4 - with: - cmd: install - - name: make sure package.lock does not exist - run: rm -f package-lock.json - - name: Git Check Clean Tree - uses: ArkadiK94/action-git-clean-tree@v1.0.3 - with: - error-reason: 'removing package-lock.json file' - - name: Install dependencies - run: yarn - - name: Git Check Clean Tree - uses: ArkadiK94/action-git-clean-tree@v1.0.3 - with: - error-reason: 'yarn' - - name: Build - run: yarn build - - name: Build Storybook - run: yarn build-storybook -o dist/storybook - - name: Git Check Clean Tree - uses: ArkadiK94/action-git-clean-tree@v1.0.3 - with: - error-reason: 'yarn build and yarn build-storybook' - - name: Clean up - if: always() - run: npm uninstall -g yarn diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 55b4a826..00000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Lint -on: - pull_request: -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Run install - uses: borales/actions-yarn@v4 - with: - cmd: install - - name: Run lint - run: yarn lint - - name: find circular dependencies - run: yarn madge --extensions js,ts --circular . diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml deleted file mode 100644 index 33ba1767..00000000 --- a/.github/workflows/playwright.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Playwright Tests -on: - pull_request: -jobs: - test: - timeout-minutes: 60 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Run install - uses: borales/actions-yarn@v4 - with: - cmd: install - - name: Install Playwright Browsers - run: yarn playwright install --with-deps - - name: Run Playwright tests - run: yarn playwright test - - uses: actions/upload-artifact@v3 - if: always() - with: - name: playwright-report - path: playwright-report/ - retention-days: 30\ - - uses: shallwefootball/s3-upload-action@master - name: Upload report to S3 - if: always() - id: s3-report - continue-on-error: true - with: - aws_key_id: ${{ secrets.AWS_KEY_ID }} - aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY}} - aws_bucket: noam-gaash.co.il - source_dir: playwright-report - destination_dir: ${{ github.run_id }}/open-bus/playwright-report - - name: output link to report to the summary - if: always() && steps.s3-report.outcome == 'success' - run: echo "link to report - https://s3.amazonaws.com/noam-gaash.co.il/$GITHUB_RUN_ID/open-bus/playwright-report/index.html" >> $GITHUB_STEP_SUMMARY - - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Install dependencies - run: yarn - - name: Build - run: yarn build diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml deleted file mode 100644 index 016ec598..00000000 --- a/.github/workflows/unittest.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Unit Tests -on: - pull_request: -jobs: - test-unit: - timeout-minutes: 60 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 20 - - name: Run install - uses: borales/actions-yarn@v4 - with: - cmd: install - - name: run the tests - run: yarn test:unit diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml new file mode 100644 index 00000000..f89f9314 --- /dev/null +++ b/.github/workflows/validate.yaml @@ -0,0 +1,133 @@ +name: Validate +on: + pull_request: + +env: + DOCKER_APP_IMAGE_NAME: 'ghcr.io/hasadna/open-bus-map-search/open-bus-map-search' + DOCKER_APP_IMAGE_TAG: 'latest' + +jobs: + verify-clean-tree: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install + - name: make sure package.lock does not exist + run: rm -f package-lock.json + - name: Git Check Clean Tree + uses: ArkadiK94/action-git-clean-tree@v1.0.3 + with: + error-reason: 'removing package-lock.json file' + - name: Install dependencies + run: yarn + - name: Git Check Clean Tree + uses: ArkadiK94/action-git-clean-tree@v1.0.3 + with: + error-reason: 'yarn' + - name: Build + run: yarn build + - name: Build Storybook + run: yarn build-storybook -o dist/storybook + - name: Git Check Clean Tree + uses: ArkadiK94/action-git-clean-tree@v1.0.3 + with: + error-reason: 'yarn build and yarn build-storybook' + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install + - name: Run lint + run: yarn lint + circular: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install + - name: find circular dependencies + run: yarn madge --extensions js,ts --circular . + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build and Export Docker image + uses: docker/build-push-action@v2 + with: + context: . + tags: ${{ env.DOCKER_APP_IMAGE_NAME }}:${{ env.DOCKER_APP_IMAGE_TAG }} + outputs: type=docker, dest=/tmp/docker-image.tar + - name: Save Docker image + uses: actions/upload-artifact@v2 + with: + name: docker-image + path: /tmp/docker-image.tar + test: + runs-on: ubuntu-latest + needs: build + steps: + - name: Download artifact + uses: actions/download-artifact@v3 + with: + name: docker-image + path: /tmp + - name: Load image + run: docker load -i /tmp/docker-image.tar + - name: Run application + run: docker run -d -p 3000:80 ${{ env.DOCKER_APP_IMAGE_NAME }}:${{ env.DOCKER_APP_IMAGE_TAG }} + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install + - run: yarn playwright install + - name: Run test + run: yarn test + - name: upload playwright artifacts + if: always() + uses: actions/upload-artifact@v2 + with: + name: playwright + path: test-results + test-unit: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 20 + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install + - name: run the tests + run: yarn test:unit + all-passed: + runs-on: ubuntu-latest + needs: [verify-clean-tree, lint, circular, test, test-unit] + steps: + - name: All passed + run: echo "All passed" diff --git a/playwright.config.ts b/playwright.config.ts index 1b9ac1ee..597114b5 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -72,7 +72,7 @@ export default defineConfig({ /* Run your local dev server before starting the tests */ webServer: { command: 'yarn start', - reuseExistingServer: !process.env.CI, + reuseExistingServer: true, timeout: 120 * 1000, port: 3000, }, diff --git a/tests/SelectorsModel.ts b/tests/SelectorsModel.ts new file mode 100644 index 00000000..bd377686 --- /dev/null +++ b/tests/SelectorsModel.ts @@ -0,0 +1,30 @@ +import { Page, Locator } from '@playwright/test' + +export default class Selectors { + _operatorSelector: Locator + _routeSelector: Locator + _stopSelector: Locator + _lineNumberSelector: Locator + + constructor(page: Page) { + this._operatorSelector = page.locator('#operator-select') + this._lineNumberSelector = page.getByPlaceholder('לדוגמא: 17א') + this._routeSelector = page + .locator('div') + .filter({ hasText: /^בחירת מסלול נסיעה/ }) + .locator('#route-select') + this._stopSelector = page.locator('#stop-select') + } + get operator() { + return this._operatorSelector + } + get lineNumber() { + return this._lineNumberSelector + } + get route() { + return this._routeSelector + } + get stop() { + return this._stopSelector + } +} diff --git a/tests/about.spec.ts b/tests/about.spec.ts index 543f9c87..ec404292 100644 --- a/tests/about.spec.ts +++ b/tests/about.spec.ts @@ -3,8 +3,8 @@ test.describe('About Page Tests', () => { test('can access about page by clicking `about` menu', async ({ page }) => { await page.goto('/') await page.getByText('אודות').click() - await expect(page).toHaveURL('http://localhost:3000/about') - const locator = await page.locator('li:has-text("אודות")') + await expect(page).toHaveURL(/about/) + const locator = await page.locator('li').filter({ hasText: 'אודות' }) await expect(locator).toHaveClass(/menu-item-selected/) }) test('page display title `מהו אתר “דאטאבוס”?`', async ({ page }) => { diff --git a/tests/clearButton.spec.ts b/tests/clearButton.spec.ts index 8f108f93..23ac6e94 100644 --- a/tests/clearButton.spec.ts +++ b/tests/clearButton.spec.ts @@ -1,74 +1,124 @@ -import { test, expect } from '@playwright/test' +import { test, expect, type Locator, type Page } from '@playwright/test' -test.afterEach(async ({ page }, testInfo) => { - if (testInfo.title === 'test in RealtimeMapPage') return - if (testInfo.title === 'test in GapsPatternsPage') { +import Selectors from './SelectorsModel' + +async function visitPage(page: Page, pageName: string, url: RegExp) { + await page.goto('/') + await page.getByText(pageName, { exact: true }).click() + await page.waitForURL(url) + await page.getByRole('progressbar').waitFor({ state: 'hidden' }) +} + +async function fillDate(page: Page, twoDateElements: boolean = false) { + if (twoDateElements) { await page.getByLabel('בחירת תאריך').nth(0).click() await page.getByRole('gridcell', { name: '1', exact: true }).first().click() await page.getByLabel('בחירת תאריך').nth(1).click() } else { await page.getByLabel('בחירת תאריך').click() } - //clear LineNumber value test await page.getByRole('gridcell', { name: '2', exact: true }).first().click() - await page.locator('#operator-select').click() - await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() - await page.getByPlaceholder('לדוגמא: 17א').fill('64') - const routeSelect = page - .locator('div') - .filter({ hasText: /^בחירת מסלול נסיעה/ }) - .locator('#route-select') - const stopSelect = page.locator('#stop-select') +} - await routeSelect.click() +async function selectLineNumberAndRoute(page: Page, lineNumber: Locator, route: Locator) { + await lineNumber.fill('64') + await route.click() await page .getByRole('option', { name: 'הרב עובדיה יוסף/שלום צלח-פתח תקווה ⟵ מסוף כרמלית/הורדה-תל אביב יפו', }) .click() - if (testInfo.title === 'test in GapsPage') { - await page.getByLabel('רק פערים').check() - await page.getByLabel('רק פערים').uncheck() - } - await page.getByPlaceholder('לדוגמא: 17א').click() - await page.getByLabel('close').locator('svg').click() - await expect(routeSelect).not.toBeVisible() - await expect(stopSelect).not.toBeVisible() - //clear Operator value test - await page.getByPlaceholder('לדוגמא: 17א').fill('64') - await routeSelect.click() - await page - .getByRole('option', { - name: 'הרב עובדיה יוסף/שלום צלח-פתח תקווה ⟵ מסוף כרמלית/הורדה-תל אביב יפו', - }) - .click() - await page.locator('#operator-select').click() - await page.getByRole('button', { name: 'Clear' }).click() - await expect(routeSelect).not.toBeVisible() - await expect(stopSelect).not.toBeVisible() -}) +} test.describe('test clearButton ', () => { test('test in TimeLinePage', async ({ page }) => { - await page.goto('/') - await page.goto('/dashboard') - await page.locator('li').filter({ hasText: 'לוח זמנים היסטורי' }).click() + await visitPage(page, 'לוח זמנים היסטורי', /timeline/) + await fillDate(page) + const { operator, lineNumber, route, stop } = new Selectors(page) + + //clear LineNumber value test + await operator.click() + await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() + await selectLineNumberAndRoute(page, lineNumber, route) + await lineNumber.click() + await page.getByLabel('close').locator('svg').click() + await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() + + //clear Operator value test + await selectLineNumberAndRoute(page, lineNumber, route) + await operator.click() + await page.getByRole('button', { name: 'Clear' }).click() + await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() }) test('test in GapsPage', async ({ page }) => { - await page.goto('/') - await page.getByText('נסיעות שלא יצאו', { exact: true }).click() + await visitPage(page, 'נסיעות שלא יצאו', /gaps/) + await fillDate(page) + const { operator, lineNumber, route, stop } = new Selectors(page) + + //clear LineNumber value test + await operator.click() + await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() + await selectLineNumberAndRoute(page, lineNumber, route) + await page.getByLabel('רק פערים').check() + await page.getByLabel('רק פערים').uncheck() + await lineNumber.click() + await page.getByLabel('close').locator('svg').click() + await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() + + //clear Operator value test + await selectLineNumberAndRoute(page, lineNumber, route) + await operator.click() + await page.getByRole('button', { name: 'Clear' }).click() + await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() }) test('test in GapsPatternsPage', async ({ page }) => { - await page.goto('/') - await page.getByText('דפוסי נסיעות שלא יצאו', { exact: true }).click() + await visitPage(page, 'דפוסי נסיעות שלא יצאו', /gaps_patterns/) + await fillDate(page, true) + const { operator, lineNumber, route, stop } = new Selectors(page) + + //clear LineNumber value test + await operator.click() + await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() + await selectLineNumberAndRoute(page, lineNumber, route) + await lineNumber.click() + await page.getByLabel('close').locator('svg').click() + await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() + + //clear Operator value test + await selectLineNumberAndRoute(page, lineNumber, route) + await operator.click() + await page.getByRole('button', { name: 'Clear' }).click() + await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() }) test('test in SingleLineMapPage', async ({ page }) => { - await page.goto('/') - await page.getByText('מפה לפי קו', { exact: true }).click() + await visitPage(page, 'מפה לפי קו', /single-line/) + await fillDate(page) + const { operator, lineNumber, route, stop } = new Selectors(page) + + //clear LineNumber value test + await operator.click() + await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() + await selectLineNumberAndRoute(page, lineNumber, route) + await lineNumber.click() + await page.getByLabel('close').locator('svg').click() + await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() + + //clear Operator value test + await selectLineNumberAndRoute(page, lineNumber, route) + await operator.click() + await page.getByRole('button', { name: 'Clear' }).click() + await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() }) test('test in RealtimeMapPage', async ({ page }) => { - await page.goto('/') - await page.getByText('מפה בזמן אמת', { exact: true }).click() + await visitPage(page, 'מפה בזמן אמת', /map/) const minutes = page.getByLabel('דקות') let getValueAttribute = await minutes.getAttribute('value') if (!getValueAttribute) return test.fail() diff --git a/tests/realtimemap.spec.ts b/tests/realtimemap.spec.ts index dbd0ce57..959fd2b8 100644 --- a/tests/realtimemap.spec.ts +++ b/tests/realtimemap.spec.ts @@ -2,8 +2,10 @@ import { test } from '@playwright/test' test('realtime-map page', async ({ page }) => { await page.goto('/') - await page.getByText('מפה בזמן אמת').click() - await page.getByLabel('בחירת תאריך, התאריך שנבחר הוא').click() + await page.getByText('מפה בזמן אמת', { exact: true }).click() + await page.waitForURL(/map/) + await page.getByRole('progressbar').waitFor({ state: 'hidden' }) + await page.getByLabel('בחירת תאריך').click() await page.getByRole('gridcell', { name: '1', exact: true }).click() await page.getByLabel('דקות').fill('6') })