@sector-labs/seo-slip
Version:
Catches SEO regressions by sampling and checking a website against a set of rules
85 lines (72 loc) • 2.71 kB
JavaScript
const { newMessage, newEmptyItemResult } = require('../reporting');
module.exports = (statusCodeRules) => {
const name = 'statusCodeChecker';
const code = (statusCodeRules || {}).code || 200;
const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const normalizeCode = (code) => (typeof code === 'number' ? [code] : code);
const normalizeExceptions = (exceptions) => {
// Output example:
// [
// { regexp: /\/new-projects/, code: [ 301, 307 ] },
// { regexp: /\/ur\/new-projects/, code: [ 404 ] },
// ]
return Object.keys(exceptions).map((key) => {
const rule = exceptions[key];
if (typeof rule === 'object' && rule.regexp === true) {
return {
regexp: new RegExp(key),
code: normalizeCode(rule.code),
};
}
return {
regexp: RegExp(`^${escapeRegExp(key)}$`),
code: normalizeCode(rule),
};
});
};
const exceptions = normalizeExceptions((statusCodeRules || {}).exceptions || {});
const findException = (path, exceptions) => {
return exceptions.find((exception) => path.match(exception.regexp));
};
return {
analysis: (queueItem, responseBody, response) => {
return {
code: queueItem.stateData.code,
path: queueItem.path,
url: queueItem.url,
referrer: queueItem.referrer,
};
},
report: (analysis) => {
return {
code: analysis.code,
path: analysis.path,
};
},
check: (analysis) => {
const result = newEmptyItemResult();
if (analysis.code === code) {
return result;
}
const exception = findException(analysis.path, exceptions);
if (exception) {
if (exception.code.indexOf(analysis.code) === -1) {
result.passed = false;
result.messages.push(
newMessage(
analysis.url,
name,
`Expected code(s)=${exception.code}, actual=${analysis.code}`
)
);
}
return result;
}
result.passed = false;
result.messages.push(
newMessage(analysis.url, name, `Expected code(s)=${code}, actual=${analysis.code}`)
);
return result;
},
};
};