Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/test-starter-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Test Starter Template

on:
push:
branches: [main]
paths:
- 'templates/starter/**'
- 'tests/**'
pull_request:
branches: [main]
paths:
- 'templates/starter/**'
- 'tests/**'

jobs:
test-starter-template:
uses: ./.github/workflows/test-template.yml
with:
template: starter
64 changes: 64 additions & 0 deletions .github/workflows/test-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Test Template(s)

on:
workflow_call:
inputs:
template:
required: true
type: string
description: 'Template name (e.g., vite, starter)'

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Install dependencies (tests)
working-directory: tests
run: npm ci

- name: Install dependencies (template)
working-directory: templates/${{ inputs.template }}
run: npm install

- name: Get Playwright version
id: playwright-version
working-directory: tests
run: echo "version=$(npm ls @playwright/test --json | jq -r '.dependencies["@playwright/test"].version')" >> $GITHUB_OUTPUT

- name: Cache Playwright browsers
uses: actions/cache@v4
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ steps.playwright-version.outputs.version }}

- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
working-directory: tests
run: npx playwright install --with-deps chromium

- name: Install Playwright system dependencies
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: npx playwright install-deps chromium

- name: Run Playwright tests
working-directory: tests
run: npm run test
env:
CI: true
TEMPLATE: ${{ inputs.template }}

- name: Upload Playwright report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report-${{ inputs.template }}-template
path: tests/playwright-report/index.html
retention-days: 30
19 changes: 19 additions & 0 deletions .github/workflows/test-vite-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Test Vite Template

on:
push:
branches: [main]
paths:
- 'templates/vite/**'
- 'tests/**'
pull_request:
branches: [main]
paths:
- 'templates/vite/**'
- 'tests/**'

jobs:
test-vite-template:
uses: ./.github/workflows/test-template.yml
with:
template: vite
7 changes: 7 additions & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Dependencies
node_modules/

# Playwright
playwright-report/
test-results/
playwright/.cache/
42 changes: 42 additions & 0 deletions tests/e2e/starter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { test, expect } from '@playwright/test';

test.describe('Starter Template', () => {
test('should load the app and display main content', async ({ page }) => {
await page.goto('/');

// Check that the page title is correct
await expect(page).toHaveTitle('Power Apps');

// Check that the main heading is visible
await expect(page.getByRole('heading', { name: 'Power + Code' })).toBeVisible();

// Check that the Power Apps and React logos are present
await expect(page.getByAltText('Power Apps logo')).toBeVisible();
await expect(page.getByAltText('React logo')).toBeVisible();
});

test('should have working counter button', async ({ page }) => {
await page.goto('/');

// Find the counter button and verify initial state
const counterButton = page.getByRole('button', { name: /count is/i });
await expect(counterButton).toBeVisible();
await expect(counterButton).toHaveText('count is 0');

// Click the button and verify the count increments
await counterButton.click();
await expect(counterButton).toHaveText('count is 1');

// Click again to verify continued functionality
await counterButton.click();
await expect(counterButton).toHaveText('count is 2');
});

test('should have theme toggle', async ({ page }) => {
await page.goto('/');

// Check that the theme toggle button exists
const themeToggle = page.getByRole('button', { name: /toggle theme/i });
await expect(themeToggle).toBeVisible();
});
});
34 changes: 34 additions & 0 deletions tests/e2e/vite.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { test, expect } from '@playwright/test';

test.describe('Vite React Template', () => {
test('should load the app and display main content', async ({ page }) => {
await page.goto('/');

// Check that the page title is correct
await expect(page).toHaveTitle('vite');

// Check that the main heading is visible
await expect(page.getByRole('heading', { name: 'Vite + React' })).toBeVisible();

// Check that the Vite and React logos are present
await expect(page.getByAltText('Vite logo')).toBeVisible();
await expect(page.getByAltText('React logo')).toBeVisible();
});

test('should have working counter button', async ({ page }) => {
await page.goto('/');

// Find the counter button and verify initial state
const counterButton = page.getByRole('button', { name: /count is/i });
await expect(counterButton).toBeVisible();
await expect(counterButton).toHaveText('count is 0');

// Click the button and verify the count increments
await counterButton.click();
await expect(counterButton).toHaveText('count is 1');

// Click again to verify continued functionality
await counterButton.click();
await expect(counterButton).toHaveText('count is 2');
});
});
90 changes: 90 additions & 0 deletions tests/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "powerappscodeapps-tests",
"private": true,
"version": "0.1.0",
"scripts": {
"test": "playwright test"
},
"devDependencies": {
"@playwright/test": "^1.40.0",
"@types/node": "^24.10.9"
}
}
55 changes: 55 additions & 0 deletions tests/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { defineConfig, devices } from "@playwright/test";
import path from "path";

const isCI = !!process.env.CI;
const template: "vite" | "starter" = process.env.TEMPLATE; // Set to 'vite' or 'starter' to run only one

const webServers = {
vite: {
name: "vite-template",
command: "npm run build && npm run preview -- --port 4173",
cwd: path.resolve(__dirname, "../templates/vite"),
url: "http://localhost:4173",
reuseExistingServer: !isCI,
},
starter: {
name: "starter-template",
command: "npm run build && npm run preview -- --port 4174",
cwd: path.resolve(__dirname, "../templates/starter"),
url: "http://localhost:4174",
reuseExistingServer: !isCI,
},
};

const projects = {
vite: {
name: "vite",
testMatch: "vite.spec.ts",
use: {
...devices["Desktop Chrome"],
baseURL: "http://localhost:4173",
},
},
starter: {
name: "starter",
testMatch: "starter.spec.ts",
use: {
...devices["Desktop Chrome"],
baseURL: "http://localhost:4174",
},
},
};

export default defineConfig({
testDir: "./e2e",
fullyParallel: true,
forbidOnly: isCI,
retries: isCI ? 2 : 0,
workers: isCI ? 1 : undefined,
reporter: isCI ? [["github"], ["html", { open: "never" }]] : "html",
use: {
trace: "on-first-retry",
},
projects: projects[template] ? [projects[template]] : Object.values(projects),
webServer: webServers[template] ?? Object.values(webServers),
});
Loading