Skip to content
Draft
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
28 changes: 18 additions & 10 deletions .github/workflows/yarn_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: Node CI

on: [pull_request]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:

Expand All @@ -11,7 +15,7 @@ jobs:
fail-fast: false
matrix:
node-version: [20.x]
# containers: [1, 2]
containers: [2]

steps:
- name: Checkout
Expand All @@ -36,20 +40,23 @@ jobs:
run: |
cd apps/nowcasting-app
yarn test --clear-cache --coverage --coverageDirectory=../..
- name: Run cypress tests
- name: Run cypress tests with Percy
# Uses the official Cypress GitHub action https://github.com/cypress-io/github-action
uses: cypress-io/github-action@v6
with:
# Starts web server for E2E tests - replace with your own server invocation
# https://docs.cypress.io/guides/continuous-integration/introduction#Boot-your-server
wait-on: 'http://localhost:3002'
wait-on-timeout: 120000
working-directory: ./apps/nowcasting-app
start: yarn start
# Records to Cypress Cloud
# https://docs.cypress.io/guides/cloud/projects#Set-up-a-project-to-record
record: true
# parallel: true # Runs test in parallel using settings above
config: chromeWebSecurity=false
browser: chrome
command: npx percy exec -- cypress run --browser chrome --record --parallel --group "E2E + Percy"
- name: Upload Cypress artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: cypress-artifacts
path: |
apps/nowcasting-app/cypress/videos
apps/nowcasting-app/cypress/screenshots
env:
AUTH0_AUDIENCE: ${{ secrets.AUTH0_AUDIENCE }}
AUTH0_BASE_URL: ${{ secrets.AUTH0_BASE_URL }}
Expand All @@ -61,6 +68,7 @@ env:
AUTH0_SECRET: ${{ secrets.AUTH0_SECRET }}
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
GITHUB_TOKEN: ${{ secrets.CYPRESS_GITHUB_TOKEN }}
NEXT_PUBLIC_API_PREFIX: ${{ secrets.NEXT_PUBLIC_API_PREFIX }}
NEXT_PUBLIC_SITES_API_PREFIX: ${{ secrets.NEXT_PUBLIC_SITES_API_PREFIX }}
Expand Down
28 changes: 28 additions & 0 deletions apps/nowcasting-app/.percy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: 2
percy:
useSystemProxy: false
skipBaseBuild: false
snapshot:
widths:
- 1280
minHeight: 720
percyCSS: ""
enableJavaScript: false
cliEnableJavaScript: true
disableShadowDOM: false
forceShadowAsLightDOM: false
responsiveSnapshotCapture: false
ignoreCanvasSerializationErrors: false
discovery:
allowedHostnames: []
disallowedHostnames: []
networkIdleTimeout: 100
scrollToBottom: false
captureMockedServiceWorker: false
retry: false
launchOptions:
closeBrowser: true
upload:
files: "**/*.{png,jpg,jpeg}"
ignore: ""
stripExtensions: false
5 changes: 4 additions & 1 deletion apps/nowcasting-app/components/button-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ interface IButtonGroup {
const ButtonGroup = ({ rightString }: IButtonGroup) => {
return (
<span className="relative z-0 w-full flex justify-end shadow-sm mx-0">
<div className="absolute left-0 top-0 items-center px-3 py-[1px] font-extrabold dash:text-xl dash:tracking-wide dash:py-1 text-white bg-black">
<div
className="absolute left-0 top-0 items-center px-3 py-[1px] font-extrabold dash:text-xl dash:tracking-wide dash:py-1 text-white bg-black"
suppressHydrationWarning
>
{rightString}
</div>
</span>
Expand Down
5 changes: 4 additions & 1 deletion apps/nowcasting-app/components/charts/forecast-header/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ export const ForecastHeadlineFigure: React.FC<{
{time && (
<>
<ClockIcon />
<p className="text-xs dash:text-sm dash:xl:text-base ml-0.5 dash:leading-none leading-none">
<p
className="text-xs dash:text-sm dash:xl:text-base ml-0.5 dash:leading-none leading-none"
suppressHydrationWarning
>
{time}
</p>
</>
Expand Down
4 changes: 3 additions & 1 deletion apps/nowcasting-app/components/map/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const Map: FC<IMap> = ({

useEffect(() => {
if (map.current) return; // initialize map only once
const isCypressEnv = window.Cypress !== undefined;
if (mapContainer.current) {
map.current = new mapboxgl.Map({
container: mapContainer.current,
Expand All @@ -52,7 +53,8 @@ const Map: FC<IMap> = ({
boxZoom: false,
zoom,
bearing,
keyboard: false
keyboard: false,
preserveDrawingBuffer: isCypressEnv // Only set this in E2E tests to allow canvas rendering
});
// Updater function to prevent state updates overriding each other in race condition on load
setMaps((m) => [...m, map.current!]);
Expand Down
5 changes: 5 additions & 0 deletions apps/nowcasting-app/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export default defineConfig({
auth0_client_secret: process.env.AUTH0_CLIENT_SECRET,
baseUrl: process.env.AUTH0_BASE_URL
},
viewportWidth: 1280,
viewportHeight: 720,
defaultCommandTimeout: 10000,
requestTimeout: 15000,
responseTimeout: 15000,
chromeWebSecurity: false,
// ...rest of the Cypress project config
projectId: process.env.CYPRESS_PROJECT_ID,
Expand Down
66 changes: 66 additions & 0 deletions apps/nowcasting-app/cypress/e2e/pvLatest.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,72 @@ describe("Load the page", () => {
// Ensure Auth0 has redirected us back to the local app.
cy.location("href").should("equal", "http://localhost:3002/");
});
it("matches the snapshot", () => {
// Set the clock to a fixed time of 2025-09-23 11:35
// This is important to ensure consistent snapshots as the data is time-dependent
// and the charts will render differently depending on the current time.
const now = new Date(2025, 8, 23, 11, 35); // Note: month is 0-indexed
cy.clock(now.getTime(), ["Date"]);
// cy.tick(1000);

// Stub API responses for data as of Tue, 23 Sep 2025 11:35:24 GMT
cy.intercept("/v0/solar/GB/national/forecast?historic=false&only_forecast_values=true&UI", {
fixture: "national_forecast.json"
}).as("getNationalForecast");
cy.intercept("/v0/solar/GB/national/pvlive?regime=in-day&UI", {
fixture: "national_pvlive.json"
}).as("getNationalPvLive");

cy.intercept(
"/v0/solar/GB/gsp/forecast/all/?historic=true&compact=true&start_datetime_utc*&end_datetime_utc*",
{
fixture: "gsp_forecast_all_history.json"
}
).as("getGspForecastAllHistory");
cy.intercept(
"/v0/solar/GB/gsp/forecast/all/?compact=true&start_datetime_utc=2025-09-23T11%3A30%3A00%2B00%3A00&UI",
{
fixture: "gsp_forecast_all_latest.json"
}
).as("getGspForecastAllLatest");

cy.intercept("/v0/solar/GB/gsp/pvlive/all?compact=true&end_datetime_utc*", {
fixture: "gsp_pvlive_history.json"
}).as("getGspPvLiveHistory");
cy.intercept(
"/v0/solar/GB/gsp/pvlive/all?regime=in-day&compact=true&compact=true&start_datetime_utc*",
{
fixture: "gsp_pvlive_latest.json"
}
).as("getGspPvLiveLatest");

cy.intercept(
"/v0/solar/GB/national/forecast?forecast_horizon_minutes=240&historic=true&only_forecast_values=true&UI",
{ fixture: "national_4_hour_forecast.json" }
).as("getNational4HourForecast");

cy.intercept("/v0/system/GB/gsp/?UI", { fixture: "gsp_list.json" }).as("getGspList");

// Load page
cy.visit("http://localhost:3002/");

// Wait for the stubbed API responses
cy.wait("@getNationalForecast");
cy.wait("@getNationalPvLive");
cy.wait("@getGspForecastAllHistory");
// cy.wait("@getGspForecastAllLatest");
cy.wait("@getGspPvLiveHistory");
cy.wait("@getGspPvLiveLatest");
cy.wait("@getNational4HourForecast");
cy.wait("@getGspList");

// Ensure Auth0 has redirected us back to the local app.
cy.location("href").should("equal", "http://localhost:3002/");
// wait for loading message to disappear
// allow up to 10 seconds for the loading message to disappear
cy.get("div.chart-data-loading-message", { timeout: 30000 }).should("not.be.visible");
cy.percySnapshot("Home - default");
});

////////////////////////////////
// GENERAL
Expand Down
Loading
Loading