Skip to content

Commit

Permalink
Merge pull request #48 from modern-sapien/storageStateWorkaround
Browse files Browse the repository at this point in the history
Storage state workaround
  • Loading branch information
modern-sapien authored Apr 16, 2024
2 parents ddcee3d + af7d30c commit 47009ab
Show file tree
Hide file tree
Showing 14 changed files with 225 additions and 30 deletions.
14 changes: 14 additions & 0 deletions next-webstore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ NEXT_PUBLIC_NODE_PRODUCTION=production npx checkly deploy

NEXT_PUBLIC_NODE_PREVIEW=preview npx checkly test --record

## New Checkly Features
Visual comparison - Beta
* npx checkly test --update-snapshots
* npx checkly test --record
* tests/visit.spec.ts

Multi-step check - Beta
* tests/multi-crud.spec.ts
* checks/multi-step.check.ts

Retry Strategy - GA & Run Parallel - Beta
* checks/resources/group.check.ts
* fixed, linear, expontential options


## Getting Started

Expand Down
3 changes: 2 additions & 1 deletion next-webstore/checkly.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const config = defineConfig({
runtimeId: '2023.09',
frequency: 60,
locations: ['us-east-1', 'eu-west-1'],
tags: ['cli', 'next-danube', `${defaults.projectEnv}`],
tags: [`thiswillbeoverwritten`],
alertChannels: [emailChannel, slackChannel, webhookChannel],
checkMatch: '*/**/*.check.ts',
ignoreDirectoriesMatch: [],
Expand All @@ -28,6 +28,7 @@ const config = defineConfig({
},
cli: {
runLocation: 'us-east-1',
// privateRunLocation: 'test-location'
},
});

Expand Down
2 changes: 2 additions & 0 deletions next-webstore/checks/api.check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ new ApiCheck(`next-danube-${defaults.projectEnv}-books-api-check`, {
url: `https://next-danube-webshop-backend${env}.vercel.app/api/v1/books`,
method: 'GET',
followRedirects: true,
bodyType: "RAW",
body: "hello",
skipSSL: false,
assertions: [AssertionBuilder.statusCode().equals(200)],
},
Expand Down
1 change: 1 addition & 0 deletions next-webstore/checks/browser.check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ new BrowserCheck(`next-danube-${defaults.projectEnv}-login`, {
new BrowserCheck(`next-danube-${defaults.projectEnv}-visit`, {
name: `Next Danube ${defaults.projectEnv} visit - browser`,
group,
tags: ["tagtest"],
frequency: Frequency.EVERY_10M,
code: {
entrypoint: path.join(__dirname, '../tests/visit.spec.ts'),
Expand Down
2 changes: 1 addition & 1 deletion next-webstore/checks/resources/alertChannels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const emailChannel = new EmailAlertChannel('email-channel-1', {
});

export const slackChannel = new SlackAlertChannel('slack-channel-1', {
url: new URL(`https://hooks.slack.com/services/${process.env.SLACK_URL_ENDING}`),
url: new URL(`https://hooks.slack.com/services/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'`),
channel: '#ops'
})

Expand Down
17 changes: 17 additions & 0 deletions next-webstore/checks/resources/maintenanceWindow.check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {
MaintenanceWindow
} from 'checkly/constructs';

// Maintenance Window
export const maintenanceWindow = new MaintenanceWindow('next-danube-maintenance-window-1', {
name: 'Next Danube Website Maintenance',
// the tag determines what is created by
tags: ['next-danube'],
// 2023-07-20 at 11 PM EST in UTC
startsAt: new Date(Date.UTC(2023, 6, 21, 4, 0, 0)), // Note: JavaScript's months are 0-indexed
// 2023-07-21 at 12 AM EST in UTC
endsAt: new Date(Date.UTC(2023, 6, 21, 5, 0, 0)),
repeatInterval: 1,
repeatUnit: 'MONTH',
repeatEndsAt: new Date(new Date().valueOf() + (2160 * 60 * 60 * 1000)), // ~three months from now
})
7 changes: 0 additions & 7 deletions next-webstore/jsconfig.json

This file was deleted.

2 changes: 1 addition & 1 deletion next-webstore/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default defineConfig({
use: {
trace: "on",
actionTimeout: 6000,
navigationTimeout: 5000
navigationTimeout: 5000,
},

projects: [
Expand Down
33 changes: 33 additions & 0 deletions next-webstore/tests/binary-payload-multi.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { test, expect } from "@playwright/test"
import crypto from "crypto"

test("Verify Binary Payloads", async ({ request }) => {
// SpaceX Launch Images
const IMAGES_TO_VERIFY = [
{
url: "https://farm1.staticflickr.com/856/28684550147_49802752b3_o.jpg",
hash: "46df689c0016e4f06746f07b83546d5e",
},
{
url: "https://farm1.staticflickr.com/927/28684552447_956a9744f1_o.jpg",
hash: "ffb011da0c7cc45413c632ccd62947cf",
},
{
url: "https://farm2.staticflickr.com/1828/29700007298_8ac5891d2c_o.jpg",
hash: "eab74946120df579967922794e387276",
},
{
url: "https://farm1.staticflickr.com/914/29700004918_31ed7b73ef_o.jpg",
hash: "5e20e98a63522a0829aa5ad0003e52c6",
},
]

for (const [index, { url, hash }] of IMAGES_TO_VERIFY.entries()) {
await test.step(`Fetch image #${index}`, async () => {
const response = await request.get(url)

const body = await response.body()
expect(crypto.createHash("md5").update(body).digest("hex")).toBe(hash)
})
}
})
66 changes: 66 additions & 0 deletions next-webstore/tests/graphql-requests.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const { test, expect } = require('@playwright/test');

test.describe('GraphQL API Tests', () => {
let apiContext;

test.beforeAll(async ({ playwright }) => {
apiContext = await playwright.request.newContext();
});

test('Test Dragons Query', async () => {
const response = await apiContext.post('https://spacex-production.up.railway.app/', {
data: {
query: `
query Dragons {
dragons {
name
first_flight
diameter {
feet
}
launch_payload_mass {
lb
}
}
}
`,
},
headers: {
'Content-Type': 'application/json',
},
});

expect(response.ok()).toBeTruthy();

const responseBody = await response.json();
expect(responseBody).toHaveProperty('data.dragons');
expect(Array.isArray(responseBody.data.dragons)).toBeTruthy();
});

test('Test Ships Query', async () => {
const response = await apiContext.post('https://spacex-production.up.railway.app/', {
data: {
query: `
query Ships {
ships {
id
model
name
type
status
}
}
`,
},
headers: {
'Content-Type': 'application/json',
},
});

expect(response.ok()).toBeTruthy();

const responseBody = await response.json();
expect(responseBody).toHaveProperty('data.ships');
expect(Array.isArray(responseBody.data.ships)).toBeTruthy();
});
});
59 changes: 51 additions & 8 deletions next-webstore/tests/login.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
import { test, expect } from "@playwright/test";
import { defaults } from "./defaults";
import { test, expect } from '@playwright/test';
import { defaults } from './defaults';
import { validateStorageState } from './utils/validateStorageState';
import { createChecklyContext } from './utils/checklyRequestContext';

const apiKey = defaults.apiKey;
const accountID = defaults.accountID;
// Declare variable we'll reference during our test
let storageState;

test.beforeAll(async () => {
// Assign storage state from env variable to test specific state
storageState = await validateStorageState(apiKey, accountID);
});

test('login', async ({ page }) => {
const context = await createChecklyContext(apiKey, accountID)

test("login", async ({ page }) => {
test.setTimeout(defaults.testTime);

await page.goto(defaults.pageUrl);

await page.getByRole("link", { name: "login" }).click();
await page.waitForLoadState("networkidle");
await page.getByRole('link', { name: 'login' }).click();
await page.waitForLoadState('networkidle');
await page.locator('input[type="email"]').click();
await page.locator('input[type="email"]').fill(defaults.testUser.email);
await page.locator('input[type="password"]').fill(defaults.testUser.password);

await page.getByRole("button", { name: "Login" }).click();
await page.getByRole('button', { name: 'Login' }).click();

const response = await page.waitForResponse((response) => {
console.log(response.url(), "response url being hit");
let response = await page.waitForResponse((response) => {
// console.log(response.url(), 'response url being hit');
return response.url().includes(`/auth/login`);
});
const responseBody = await response.json();
Expand All @@ -24,4 +38,33 @@ test("login", async ({ page }) => {

expect(success).toBe(true);
expect(token).toBeDefined();

const storage = await page.context().storageState();

// stringify storage to before updating environment variable
const stringifiedStorage = JSON.stringify(storage);

const unixTimestamp = Math.floor(Date.now() / 1000);

let responseStorage = await context.put(`variables/DEV_STORAGE_STATE`, {
data: {
key: `DEV_STORAGE_STATE`,
value: `${stringifiedStorage}`,
},
});

let responseTime = await context.put(`variables/DEV_COOKIE_TIME`, {
data: {
key: `DEV_COOKIE_TIME`,
value: `${unixTimestamp}`,
},
});

let responseTimeJSON = await responseTime.json()
let responseStorageJSON = await responseStorage.json();

console.log(responseTimeJSON.value, 'unix response time')
console.log(responseStorageJSON.value, 'storage JSON');


});
12 changes: 0 additions & 12 deletions next-webstore/tests/multi-crud.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,18 @@ import { test, expect } from "@playwright/test"
const baseUrl = "https://crudapi.co.uk/api/v1/todo"

const headers = {
// Learn more about using environment variables here: https://www.checklyhq.com/docs/api-checks/variables
Authorization: `Bearer ${process.env.CRUD_API_KEY}`,
"Content-Type": "application/json",
}

/**
* Share state between hooks and test.steps
*/
let createdResources = null

/**
* Use `beforeAll` as a setup script
* Make sure there's no Todo task prior
*/
test.beforeAll(async ({ request }) => {
const response = await request.get(baseUrl, { headers })
const { items } = await response.json()
expect(items.length).toEqual(0)
})

/**
* Use `afterAll` as a teardown script
* Remove the created Todo before the check ends
*/
test.afterAll(async ({ request }) => {
if (createdResources) {
const response = await request.delete(baseUrl, {
Expand Down
12 changes: 12 additions & 0 deletions next-webstore/tests/utils/checklyRequestContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { request } from '@playwright/test';

export async function createChecklyContext(apiKey, accountID) {
return await request.newContext({
baseURL: 'https://api.checklyhq.com/v1/',
extraHTTPHeaders: {
Authorization: `Bearer ${apiKey}`,
'x-checkly-account': `${accountID}`,
'Content-Type': 'application/json',
},
});
}
25 changes: 25 additions & 0 deletions next-webstore/tests/utils/validateStorageState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { createChecklyContext } from '../utils/checklyRequestContext';

export async function validateStorageState(apiKey, accountID) {
const context = await createChecklyContext(apiKey, accountID);

let responseTime = await context.get(`variables/DEV_COOKIE_TIME`);
let responseData = await responseTime.json();
const variableUnixTime = responseData.value; // Assuming the value is already in seconds
const unixCurrentTime = Math.floor(Date.now() / 1000);

// Calculate the difference in seconds
const differenceInSeconds = unixCurrentTime - variableUnixTime;

// Check if the difference is greater than or equal to 3600 seconds (1 hour)
if (differenceInSeconds >= 3600) {
throw new Error('More than an hour has passed since DEV_COOKIE_TIME was updated.');
} else {
let responseStorageState = await context.get(`variables/DEV_STORAGE_STATE`);
let responseData = await responseStorageState.json();
const handledStorageState = JSON.parse(responseData.value);

// Return the storage state
return handledStorageState;
}
}

0 comments on commit 47009ab

Please sign in to comment.