-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
10 changed files
with
5,894 additions
and
543 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ yarn-debug.log* | |
yarn-error.log* | ||
|
||
# local env files | ||
.env | ||
.env*.local* | ||
|
||
# vercel | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
v20 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
const aws4 = require('aws4'); | ||
const axios = require('axios').default; | ||
const { format } = require('date-fns'); | ||
|
||
const S3_BUCKET_NAME = process.env.PMC_SCREENSHOT_DASHBOARD_S3_BUCKET_NAME; | ||
const AWS_REGION = process.env.PMC_SCREENSHOT_DASHBOARD_BUCKET_REGION; | ||
const ACCESS_KEY_ID = process.env.PMC_SCREENSHOT_DASHBOARD_ACCESS_KEY_ID; | ||
const SECRET_ACCESS_KEY = process.env.PMC_SCREENSHOT_DASHBOARD_SECRET_ACCESS_KEY; | ||
|
||
// Define timestamp for folder. | ||
const now = new Date(); | ||
const timestamp = format(now, 'yyyy-MM-dd-HH:mm:ss'); | ||
|
||
/** | ||
* Capture screenshots and upload them to S3. | ||
* | ||
* @param {?} page | ||
* @param {?string} url | ||
*/ | ||
export async function captureAndUploadScreenshots ({ | ||
page, | ||
url = null, | ||
}) { | ||
|
||
// Hide ads. | ||
const urlObj = new URL( url ); | ||
urlObj.searchParams.set( 'skconfig', 's::true' ); | ||
url = urlObj.toString(); | ||
|
||
// Close OneTrust. | ||
await page.addScriptTag({ content: 'window.OneTrust.Close();' }); | ||
|
||
const bauModal = await page.$( 'div.tp-modal .tp-close' ); | ||
if ( bauModal ) { | ||
await bauModal.click(); | ||
} | ||
|
||
await page.setViewportSize({ height: 1200, width: 1300 }); | ||
await page.goto(url || 'https://google.com' ); | ||
const desktopScreenshot = await page.screenshot({ fullPage: true, path: 'desktopScreenshot.jpg' }); | ||
await processScreenshot({ | ||
screenshot: desktopScreenshot, | ||
name: 'desktop', | ||
url, | ||
}); | ||
|
||
await page.setViewportSize({ height: 1200, width: 800 }); | ||
await page.goto(url || 'https://google.com' ); | ||
const tabletScreenshot = await page.screenshot({ fullPage: true, path: 'tabletScreenshot.jpg' }); | ||
processScreenshot({ | ||
screenshot: tabletScreenshot, | ||
name: 'tablet', | ||
url, | ||
}); | ||
|
||
await page.setViewportSize({ height: 1200, width: 400 }); | ||
await page.goto(url || 'https://google.com' ); | ||
const mobileScreenshot = await page.screenshot({ fullPage: true, path: 'mobileScreenshot.jpg' }); | ||
processScreenshot({ | ||
screenshot: mobileScreenshot, | ||
name: 'mobile', | ||
url, | ||
}); | ||
|
||
// @todo Include the screenshot urls in this response? | ||
return { | ||
success: true, | ||
}; | ||
} | ||
|
||
/** | ||
* Upload the screenshot to S3. | ||
* | ||
* @param {string} name Name of the file. | ||
* @param {string} screenshot File data. | ||
* @param {string} url URL for the screenshot. | ||
*/ | ||
const processScreenshot = async ({ | ||
name, | ||
screenshot, | ||
url, | ||
}) => { | ||
const pathParts = getPathPartsByUrl(url); | ||
if ( ! pathParts ) { | ||
return false; | ||
} | ||
|
||
const { hostname, pathname } = pathParts; | ||
|
||
const requestOptions = { | ||
host: `${S3_BUCKET_NAME}.s3.${AWS_REGION}.amazonaws.com`, | ||
method: 'PUT', | ||
path: `/screenshots/${hostname}/${pathname}/${timestamp}/${name}.jpeg`, | ||
body: screenshot, | ||
headers: { | ||
'Content-Type': 'image/jpeg', | ||
}, | ||
}; | ||
|
||
const creds = { | ||
accessKeyId: ACCESS_KEY_ID, | ||
secretAccessKey: SECRET_ACCESS_KEY, | ||
}; | ||
|
||
const opts = aws4.sign(requestOptions, creds); | ||
|
||
await request(opts); | ||
|
||
// If this fails, the aws4 library will throw an error. Otherwise assume | ||
// success. | ||
return true; | ||
} | ||
|
||
/** | ||
* Fire the S3 upload request. | ||
* | ||
* @param {object} opts Request options. | ||
*/ | ||
async function request(opts) { | ||
try { | ||
return await axios({ | ||
method: opts.method || 'GET', | ||
url: `https://${opts.host}${opts.path}`, | ||
headers: opts.headers || {}, | ||
data: opts.body || '', | ||
}); | ||
} catch (error) { | ||
console.log('Error', error); | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* Parse url and return a pathname and hostname sanitized for S3. | ||
* | ||
* @type {object|boolean} | ||
*/ | ||
const getPathPartsByUrl = (url) => { | ||
try { | ||
const { hostname, pathname } = new URL(url); | ||
return { | ||
pathname: pathname.replace(/[^a-zA-Z0-9]/g, '_'), | ||
hostname: hostname.replace(/[^a-zA-Z0-9]/g, '_'), | ||
}; | ||
} catch (error) { | ||
return false; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import * as path from 'path'; | ||
import { BrowserCheck, CheckGroup } from 'checkly/constructs'; | ||
|
||
/** | ||
* Screenshots group. | ||
*/ | ||
export const pmcWaybackMachineGroup = new CheckGroup( 'groups-pmc-wayback-machine', { | ||
name: 'PMC Wayback Machine', | ||
tags: [ 'screenshots', 'pmc-wayback-machine' ], | ||
environmentVariables: [], | ||
activated: true, | ||
locations: [ 'us-east-1', 'eu-west-1' ], | ||
concurrency: 100, | ||
} ); | ||
|
||
/** | ||
* Temporary list of urls copied from the yml. | ||
* | ||
* @todo Do we want to read the yml file or update it to use JSON? | ||
* | ||
* @type {Array} | ||
*/ | ||
const urls = [ | ||
'https://variety.com', | ||
'https://variety.com/2024/tv/entertainers/snl-marcello-hernandez-dave-chappelle-saturday-night-live-1236096469/', | ||
'https://variety.com/v/film/', | ||
'https://variety.com/search/?q=marvel', | ||
'https://variety.com/author/michael-schneider/', | ||
'https://footwearnews.com', | ||
'https://footwearnews.com/2023/shop/best-sneakers-for-men-1203435445/', | ||
'https://footwearnews.com/category/focus/athletic-outdoor/', | ||
'https://footwearnews.com/brand/nike/', | ||
'https://footwearnews.com/2023/business/earnings/nike-q3-earnings-2023-1203437116/', | ||
]; | ||
|
||
/** | ||
* Create a Checkly BrowserCheck for each url. | ||
*/ | ||
for (const url of urls) { | ||
const cleanedUrl = url | ||
.replace('https://', '') // Remove protocol. | ||
.replace('http://', '') // Remove protocol. | ||
.replace(/[^a-zA-Z0-9]/g, '_'); // Replace unsupported characters. | ||
|
||
new BrowserCheck(`screenshot-${cleanedUrl}`, { | ||
name: `Screenshot: ${cleanedUrl}`, | ||
locations: ['us-east-1', 'eu-west-1'], | ||
group: pmcWaybackMachineGroup, | ||
environmentVariables: [ | ||
{ key: 'SCREENSHOT_URL', value: url }, | ||
], | ||
code: { | ||
entrypoint: path.join(process.cwd(), '__checks__', 'screenshots-test.spec.ts'), | ||
}, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { captureAndUploadScreenshots } from './helpers/capture-and-upload-screenshots'; | ||
|
||
const { expect, test } = require('@playwright/test'); | ||
|
||
// Configure the Playwright Test timeout to 210 seconds, | ||
// ensuring that longer tests conclude before Checkly's browser check timeout of 240 seconds. | ||
// The default Playwright Test timeout is set at 30 seconds. | ||
// For additional information on timeouts, visit: https://checklyhq.com/docs/browser-checks/timeouts/ | ||
test.setTimeout(210000) | ||
|
||
// Set the action timeout to 10 seconds to quickly identify failing actions. | ||
// By default Playwright Test has no timeout for actions (e.g. clicking an element). | ||
test.use({ actionTimeout: 10000 }) | ||
|
||
/** | ||
* Use a test to run our screenshot logic. | ||
* | ||
* @todo Fail the test if the screenshot url 404s. | ||
*/ | ||
test('wait for the url to load and capture screenshots', async ({ page }) => { | ||
|
||
const url = process.env.SCREENSHOT_URL ?? ''; | ||
test.skip( 0 === url.length ); // No urls found. | ||
|
||
const result = await captureAndUploadScreenshots({ page, url }); | ||
expect(result?.success, 'Screenshots did not capture successfully').toBe(true); | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { defineConfig } from 'checkly'; | ||
import { BrowserCheck, Frequency } from 'checkly/constructs'; | ||
|
||
export default defineConfig({ | ||
projectName: 'PMC Wayback Machine', | ||
logicalId: 'pmc-wayback-machine', | ||
repoUrl: 'https://github.com/penske-media-corp/pmc-wayback-machine', | ||
checks: { | ||
activated: true, | ||
muted: false, | ||
runtimeId: '2024.02', | ||
frequency: Frequency.EVERY_24H, | ||
locations: [ 'us-east-1', 'eu-west-1' ], | ||
checkMatch: '__checks__/**.check.ts', | ||
}, | ||
cli: { | ||
runLocation: 'eu-west-1', | ||
}, | ||
}); |
Oops, something went wrong.