Skip to content

Commit

Permalink
Fix URL filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
daun committed Sep 13, 2023
1 parent 6543d97 commit 2f97c80
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 33 deletions.
39 changes: 13 additions & 26 deletions src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { chromium } from 'playwright'
import type { Browser, Page } from 'playwright'
import Crawler from 'crawler'

import { isAssetUrl, isHtmlContentType, isLocalUrl, isValidUrl, wait } from './util.js'
import { isAssetUrl, isHtmlContentType, isLocalUrl, isValidUrl, removeHash, wait } from './util.js'

type Styles = Record<string, string>[]

Expand Down Expand Up @@ -60,44 +60,31 @@ async function addAnimatingClass(page: Page) {
})
}

async function validateTransitionDurationStyles(page: Page, url: string, selector: string) {
export async function validateTransitionDuration(page: Page, selector: string) {
const transitionDurations = await getStyleProperty(page, selector, 'transition-duration')
const missingDurations = transitionDurations
.map(style => parseFloat(style['transition-duration']))
.filter(duration => !duration)
if (missingDurations.length) {
return {
text: 'Animated element has transition-duration set to 0s',
expected: '> 0s',
received: missingDurations[0],
page: url,
}
throw new Error(`Missing transition duration on element: ${selector}`)
}
}

async function validateTransitionStyles(page: Page, url: string, selector: string, changedStyles: string[]) {
export async function validateTransitionStyles(page: Page, selector: string, changedStyles: string[]) {
const duration = await getStyleProperty(page, selector, 'transition-duration')
const stylesBefore = await getStyleProperties(page, selector, changedStyles)
await addAnimatingClass(page)
await wait(1000)
const stylesAfter = await getStyleProperties(page, selector, changedStyles)
const styles = mergeStyles(duration, stylesBefore, stylesAfter)

return styles.map(element => {
for (const element of styles) {
const changed = Object.keys(element.before).map(key => element.before[key] !== element.after[key])
const atLeastOneChanged = changed.reduce((c, a) => a || c, false)

if (!atLeastOneChanged) {
return {
text: 'At least one animated style property must change with class "is-animating"',
expected: `Not ${JSON.stringify(element.before)}`,
received: JSON.stringify(element.after),
page: url,
}
throw new Error(`Missing expected style change on element: ${selector} (${changedStyles.join(', ')})`)
}

return false
}).filter(i => i)[0]
}
}

function mergeStyles(transitionDuration: Styles, before: Styles[], after: Styles[]) {
Expand All @@ -109,7 +96,7 @@ function mergeStyles(transitionDuration: Styles, before: Styles[], after: Styles
},
after: {
...after.map((item) => ({...item[index]})).reduce((c, a) => ({ ...a, ...c })),
},
}
}
})
}
Expand All @@ -136,11 +123,11 @@ export function crawlSiteForUrls(url: string): Promise<string[]> {
}
urls.push(request.uri.href)
$('a[href]:not([download])').each((i, el) => {
const href = String($(el).attr('href')).trim()
if (href) {
const link = new URL(href, base)
if (isValidUrl(link) && isLocalUrl(link, base) && !isAssetUrl(link)) {
crawler.queue(link.href)
const href = removeHash(String($(el).attr('href')).trim())
const url = new URL(href, base)
if (isValidUrl(url)) {
if (!urls.includes(url.href) && isLocalUrl(url, base) && !isAssetUrl(url)) {
crawler.queue(url.href)
}
}
})
Expand Down
43 changes: 36 additions & 7 deletions src/commands/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import chalk from 'chalk'
import { Listr, ListrTask } from 'listr2'
import { Browser } from 'playwright'

import { crawlSiteForUrls, createBrowser, visitPage } from '../browser.js'
import { isUrl, isValidUrl, n } from '../util.js'
import { crawlSiteForUrls, createBrowser, validateTransitionDuration, validateTransitionStyles, visitPage } from '../browser.js'
import { getLocalUrl, isUrl, isValidUrl, n } from '../util.js'
import { loadConfig, type Config } from '../config.js'

interface Ctx {
Expand Down Expand Up @@ -91,26 +91,38 @@ export default class Validate extends Command {
const tasks: ListrTask<Ctx>[] = [
{
title: 'Setting up',
task: async (ctx, task) => task.newListr(() => [
task: async (ctx, task) => {
return task.newListr(() => [
{
title: 'Launching browser',
task: async (ctx) => {
const { browser, teardown } = await createBrowser()
ctx.browser = browser
ctx.teardown = teardown
}
},
]
)
}
])
}
},
{
title: 'Compiling pages',
task: async (ctx, task): Promise<void> => {
task: async (ctx, task) => {
const { source, urls } = await this.getPageUrls(ctx)
ctx.urls = urls
task.title = chalk`Found {green ${urls.length} ${n(urls.length, 'page')}} in {magenta ${source}}`
}
},
{
title: 'Validating pages',
task: async (ctx, task) => {
const subtasks = ctx.urls.map((url, index) => ({
title: `Validating ${getLocalUrl(url)}`,
task: async () => await this.validatePage(ctx, url)
}))
return task.newListr(subtasks, { concurrent: ctx.config.validate.parallel })
// task.title = chalk`Validated {green ${urls.length} ${n(urls.length, 'page')}} in {magenta ${source}}`
}
},
{
title: 'Shutting down',
task: async (ctx, task) => task.newListr(() => [
Expand Down Expand Up @@ -203,4 +215,21 @@ export default class Validate extends Command {
// return (JSON.parse(parser.toJson(sitemap)).urlset.url.map(i => i.loc))
return []
}

async validatePage(ctx: Ctx, url: string): Promise<void> {
const { tests, styles } = ctx.config.validate
const { animationSelector } = ctx.config.swup
const { browser } = ctx
const page = await visitPage(browser!, url)
const checks = {
'transition-duration': () => validateTransitionDuration(page, animationSelector),
'transition-styles': () => validateTransitionStyles(page, animationSelector, styles)
}
const actualChecks = Object.entries(checks).filter(
([test]) => !tests.length || tests.includes('all') || tests.includes(test)
)
for (const [, test] of actualChecks) {
await test()
}
}
}
9 changes: 9 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,12 @@ export function isHtmlContentType(headers: Record<string, string>): boolean {
const contentType = headers['content-type'] || headers['Content-Type']
return Boolean(contentType && contentType.match(/\bx?html\b/i))
}

export function removeHash(url: URL | string): string {
return String(url).replace(/#.*$/, '')
}

export function getLocalUrl(url: URL | string): string {
const { pathname, search } = new URL(String(url))
return pathname + search
}

0 comments on commit 2f97c80

Please sign in to comment.