Skip to content
Closed
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
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: Screenly/edge-apps-actions/checks@v1
- uses: Screenly/edge-apps-actions/checks@v26.10.0
7 changes: 4 additions & 3 deletions .github/workflows/initialize-edge-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ jobs:
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ inputs.environment == 'production' && 'main' || github.ref }}
- uses: Screenly/edge-apps-actions/initialize@v1
- uses: Screenly/edge-apps-actions/initialize@v26.10.0
with:
screenly_api_token: ${{ secrets.SCREENLY_API_TOKEN }}
edge_app_name: ${{ inputs.edge_app_name }}
edge_app_title: ${{ inputs.edge_app_title }}
environment: ${{ inputs.environment }}
# First create: leave STAGE_EDGE_APP_ID / PRODUCTION_EDGE_APP_ID unset
# so this is "". After create: set the matching var to the printed id.
edge_app_id: ${{ (inputs.environment == 'production' && vars.PRODUCTION_EDGE_APP_ID) || (inputs.environment == 'stage' && vars.STAGE_EDGE_APP_ID) || '' }}
26 changes: 20 additions & 6 deletions .github/workflows/update-edge-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,48 @@ on:
workflow_dispatch:
push:
branches:
- development
- main
tags:
- 'v[0-9]*'

run-name: Updating Clock App in ${{ github.event_name == 'workflow_dispatch' && 'stage' || (github.ref == 'refs/heads/main' && 'production' || 'stage') }}
run-name: Updating Clock App in ${{ (github.event_name == 'push' && !github.event.deleted && startsWith(github.ref, 'refs/tags/v')) && 'production' || 'stage' }}

jobs:
deploy-stage:
name: Updating Clock App in stage
runs-on: ubuntu-latest
if: (github.event_name == 'push' && github.ref == 'refs/heads/development') || github.event_name == 'workflow_dispatch'
if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'workflow_dispatch'
environment: stage
steps:
- uses: actions/checkout@v7
- uses: Screenly/edge-apps-actions/update@v1
- uses: Screenly/edge-apps-actions/update@v26.10.0
with:
screenly_api_token: ${{ secrets.SCREENLY_API_TOKEN }}
environment: stage
delete_missing_settings: 'true'
edge_app_id: ${{ vars.STAGE_EDGE_APP_ID }}

deploy-production:
name: Updating Clock App in production
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
if: github.event_name == 'push' && !github.event.deleted && startsWith(github.ref, 'refs/tags/v')
environment: production
steps:
- uses: actions/checkout@v7
- uses: Screenly/edge-apps-actions/update@v1
with:
fetch-depth: 0
- name: Verify tag is on the default branch
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
git fetch --no-tags origin "$DEFAULT_BRANCH"
if ! git merge-base --is-ancestor HEAD FETCH_HEAD; then
echo "Tag $GITHUB_REF_NAME is not on $DEFAULT_BRANCH; refusing to deploy to production."
exit 1
fi
- uses: Screenly/edge-apps-actions/update@v26.10.0
with:
screenly_api_token: ${{ secrets.SCREENLY_API_TOKEN }}
environment: production
delete_missing_settings: 'true'
edge_app_id: ${{ vars.PRODUCTION_EDGE_APP_ID }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ node_modules/
dist/
*.log
.DS_Store
mock-data.yml
static/js/*.js
static/js/*.js.map
screenshots/*.png
.env
221 changes: 132 additions & 89 deletions bun.lock

Large diffs are not rendered by default.

154 changes: 126 additions & 28 deletions e2e/screenshots.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { test } from '@playwright/test'
import { test, type Browser } from '@playwright/test'
import {
createMockScreenlyForScreenshots,
getScreenshotsDir,
Expand All @@ -7,44 +7,142 @@ import {
setupOpenWeatherMocks,
setupScreenlyJsMock,
} from '@screenly/edge-apps/test/screenshots'
import { mockGeocodingResponse, mockWeatherResponse } from './weather-mocks'
import {
createGeocodingResponse,
createWeatherResponse,
NEW_YORK,
type MockCity,
} from './weather-mocks'
import path from 'path'

const { screenlyJsContent } = createMockScreenlyForScreenshots(
interface ScreenshotVariant {
city: MockCity
timezone: string
locale: string
style: string
}

const DEFAULT_VARIANT: ScreenshotVariant = {
city: NEW_YORK,
timezone: 'America/New_York',
locale: 'en',
style: 'traditional',
}

// Extra app store screenshots, only rendered at 1080p landscape and portrait
const STORE_RESOLUTIONS = [
{ width: 1920, height: 1080 },
{ width: 1080, height: 1920 },
]

const STORE_VARIANTS: ScreenshotVariant[] = [
{
coordinates: [40.7128, -74.006],
location: 'New York, NY',
city: {
name: 'Berlin',
country: 'DE',
coordinates: [52.52, 13.405],
temperature: 8,
},
timezone: 'Europe/Berlin',
locale: 'de',
style: 'modern',
},
{
override_timezone: 'America/New_York',
override_locale: 'en',
openweathermap_api_key: 'mock-api-key',
city: {
name: 'Paris',
country: 'FR',
coordinates: [48.8566, 2.3522],
temperature: 11,
},
timezone: 'Europe/Paris',
locale: 'fr',
style: 'minimal',
},
)
{
city: {
name: 'Madrid',
country: 'ES',
coordinates: [40.4168, -3.7038],
temperature: 15,
},
timezone: 'Europe/Madrid',
locale: 'es',
style: 'traditional',
},
{
city: {
name: 'Dubai',
country: 'AE',
coordinates: [25.2048, 55.2708],
temperature: 28,
},
timezone: 'Asia/Dubai',
locale: 'ar',
style: 'traditional',
},
]

for (const { width, height } of RESOLUTIONS) {
test(`screenshot ${width}x${height}`, async ({ browser }) => {
const screenshotsDir = getScreenshotsDir()
async function takeScreenshot(
browser: Browser,
{ width, height }: { width: number; height: number },
variant: ScreenshotVariant,
fileName: string,
) {
const { screenlyJsContent } = createMockScreenlyForScreenshots(
{
coordinates: variant.city.coordinates,
location: `${variant.city.name}, ${variant.city.country}`,
},
{
override_timezone: variant.timezone,
override_locale: variant.locale,
style: variant.style,
openweathermap_api_key: 'mock-api-key',
},
)

const context = await browser.newContext({ viewport: { width, height } })
const page = await context.newPage()
const context = await browser.newContext({ viewport: { width, height } })
const page = await context.newPage()

// Setup mocks
await setupClockMock(page)
await setupScreenlyJsMock(page, screenlyJsContent)
await setupOpenWeatherMocks(page, {
geocoding: mockGeocodingResponse,
weather: mockWeatherResponse,
})
await setupClockMock(page)
await setupScreenlyJsMock(page, screenlyJsContent)
await setupOpenWeatherMocks(page, {
geocoding: createGeocodingResponse(variant.city),
weather: createWeatherResponse(variant.city),
})

await page.goto('/')
await page.waitForLoadState('networkidle')
await page.goto('/')
await page.waitForLoadState('networkidle')

await page.screenshot({
path: path.join(screenshotsDir, `${width}x${height}.png`),
fullPage: false,
})
await page.screenshot({
path: path.join(getScreenshotsDir(), fileName),
fullPage: false,
})

await context.close()
}

for (const resolution of RESOLUTIONS) {
const { width, height } = resolution

await context.close()
test(`screenshot ${width}x${height}`, async ({ browser }) => {
await takeScreenshot(
browser,
resolution,
DEFAULT_VARIANT,
`${width}x${height}.png`,
)
})
}

for (const resolution of STORE_RESOLUTIONS) {
const { width, height } = resolution

for (const variant of STORE_VARIANTS) {
const name = `${width}x${height}-${variant.locale}-${variant.style}`

test(`screenshot ${name}`, async ({ browser }) => {
await takeScreenshot(browser, resolution, variant, `${name}.png`)
})
}
}
Loading
Loading