Skip to content

Commit

Permalink
feat: adding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreiAlexandruParaschiv committed Aug 8, 2024
1 parent e9f7abe commit c7cd1ff
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 156 deletions.
6 changes: 3 additions & 3 deletions .nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"text"
],
"check-coverage": true,
"lines": 95,
"branches": 95,
"statements": 95,
"lines": 97,
"branches": 97,
"statements": 97,
"all": true,
"include": [
"src/**/*.js"
Expand Down
2 changes: 1 addition & 1 deletion src/canonical/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { fetch } from '../support/utils.js';
import { AuditBuilder } from '../common/audit-builder.js';
import { noopUrlResolver } from '../common/audit.js';

const CANONICAL_CHECKS = Object.freeze({
export const CANONICAL_CHECKS = Object.freeze({
CANONICAL_TAG_EXISTS: {
check: 'canonical-tag-exists',
explanation: 'The canonical tag is missing, which can lead to duplicate content issues and negatively affect SEO rankings.',
Expand Down
174 changes: 22 additions & 152 deletions test/audits/canonical.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import sinonChai from 'sinon-chai';
import nock from 'nock';
import {
getTopPagesForSiteId, validateCanonicalTag, validateCanonicalFormat,
validateCanonicalRecursively, canonicalAuditRunner,
validateCanonicalRecursively, canonicalAuditRunner, CANONICAL_CHECKS,
} from '../../src/canonical/handler.js';

chai.use(sinonChai);
Expand Down Expand Up @@ -93,7 +93,7 @@ describe('Canonical URL Tests', () => {
expect(result.checks).to.deep.include({
check: 'canonical-tag-exists',
success: false,
explanation: 'The canonical tag is missing, which can lead to duplicate content issues and negatively affect SEO rankings.',
explanation: CANONICAL_CHECKS.CANONICAL_TAG_EXISTS.explanation,
});
expect(log.info).to.have.been.called;
});
Expand All @@ -105,7 +105,7 @@ describe('Canonical URL Tests', () => {
expect(result.checks).to.deep.include({
check: 'url-defined',
success: false,
explanation: 'The URL is undefined or null, which prevents the canonical tag validation process.',
explanation: CANONICAL_CHECKS.URL_UNDEFINED.explanation,
});
expect(log.error).to.have.been.calledWith('URL is undefined or null');
});
Expand All @@ -117,7 +117,11 @@ describe('Canonical URL Tests', () => {
const result = await validateCanonicalTag(url, log);

expect(result.canonicalUrl).to.be.null;
expect(result.checks).to.deep.include({ check: 'canonical-url-fetch-error', success: false, explanation: 'There was an error fetching the canonical URL, which prevents validation of the canonical tag.' });
expect(result.checks).to.deep.include({
check: 'canonical-url-fetch-error',
success: false,
explanation: CANONICAL_CHECKS.CANONICAL_URL_FETCH_ERROR.explanation,
});
});

it('should handle empty canonical tag', async () => {
Expand All @@ -131,7 +135,7 @@ describe('Canonical URL Tests', () => {
expect(result.checks).to.deep.include({
check: 'canonical-tag-nonempty',
success: false,
explanation: 'The canonical tag is empty. It should point to the preferred version of the page to avoid content duplication.',
explanation: CANONICAL_CHECKS.CANONICAL_TAG_NONEMPTY.explanation,
});
expect(log.info).to.have.been.calledWith(`Empty canonical tag found for URL: ${url}`);
});
Expand All @@ -146,7 +150,7 @@ describe('Canonical URL Tests', () => {
expect(result.checks).to.deep.include({
check: 'canonical-tag-once',
success: false,
explanation: 'Multiple canonical tags detected, which confuses search engines and can dilute page authority.',
explanation: CANONICAL_CHECKS.CANONICAL_TAG_ONCE.explanation,
});
});

Expand All @@ -160,7 +164,7 @@ describe('Canonical URL Tests', () => {
expect(result.checks).to.deep.include({
check: 'canonical-tag-in-head',
success: false,
explanation: 'The canonical tag must be placed in the head section of the HTML document to ensure it is recognized by search engines.',
explanation: CANONICAL_CHECKS.CANONICAL_TAG_IN_HEAD.explanation,
});
expect(log.info).to.have.been.calledWith('Canonical tag is not in the head section');
});
Expand All @@ -177,7 +181,6 @@ describe('Canonical URL Tests', () => {
{ check: 'canonical-url-absolute', success: true },
{ check: 'canonical-url-same-protocol', success: true },
{ check: 'canonical-url-same-domain', success: true },
// { check: 'canonical-url-lowercased', success: true },
]);
});

Expand All @@ -189,7 +192,7 @@ describe('Canonical URL Tests', () => {
expect(result).to.deep.include.members([{
check: 'url-defined',
success: false,
explanation: 'The URL is undefined or null, which prevents the canonical tag validation process.',
explanation: CANONICAL_CHECKS.URL_UNDEFINED.explanation,
}]);
});

Expand All @@ -201,7 +204,7 @@ describe('Canonical URL Tests', () => {
expect(result).to.deep.include({
check: 'url-defined',
success: false,
explanation: 'The URL is undefined or null, which prevents the canonical tag validation process.',
explanation: CANONICAL_CHECKS.URL_UNDEFINED.explanation,
});
expect(log.error).to.have.been.calledWith('Invalid URL: invalid-url');
});
Expand All @@ -214,7 +217,7 @@ describe('Canonical URL Tests', () => {
expect(result).to.deep.include({
check: 'canonical-url-lowercased',
success: false,
explanation: 'Canonical URLs should be in lowercase to prevent duplicate content issues since URLs are case-sensitive.',
explanation: CANONICAL_CHECKS.CANONICAL_URL_LOWERCASED.explanation,
});
expect(log.info).to.have.been.calledWith('Canonical URL is not lowercased: https://example.com/UpperCase');
});
Expand All @@ -227,7 +230,7 @@ describe('Canonical URL Tests', () => {
expect(result).to.deep.include({
check: 'canonical-url-same-domain',
success: false,
explanation: 'The canonical URL should match the domain of the page to avoid signaling to search engines that the content is duplicated elsewhere.',
explanation: CANONICAL_CHECKS.CANONICAL_URL_SAME_DOMAIN.explanation,
});
expect(log.info).to.have.been.calledWith('Canonical URL https://another.com does not have the same domain as base URL https://example.com');
});
Expand All @@ -240,12 +243,11 @@ describe('Canonical URL Tests', () => {
expect(result).to.deep.include({
check: 'canonical-url-same-protocol',
success: false,
explanation: 'The canonical URL must use the same protocol (HTTP or HTTPS) as the page to maintain consistency and avoid indexing issues.',
explanation: CANONICAL_CHECKS.CANONICAL_URL_SAME_PROTOCOL.explanation,
});
expect(log.info).to.have.been.calledWith('Canonical URL https://example.com uses a different protocol than base URL http://example.com');
});

// FAILING TEST
it('should fail if the canonical URL is not absolute', () => {
const canonicalUrl = '/relative/url';
const baseUrl = 'http://example.com';
Expand All @@ -255,11 +257,10 @@ describe('Canonical URL Tests', () => {
expect(result).to.deep.include({
check: 'canonical-url-absolute',
success: false,
explanation: 'Canonical URLs must be absolute to avoid ambiguity in URL resolution and ensure proper indexing by search engines.',
explanation: CANONICAL_CHECKS.CANONICAL_URL_ABSOLUTE.explanation,
});
});

// FAILING TEST
it('should pass if the canonical URL points to itself', async () => {
const url = 'http://example.com';
const html = `<html><head><link rel="canonical" href="${url}"></head><body></body></html>`;
Expand All @@ -279,7 +280,6 @@ describe('Canonical URL Tests', () => {
expect(log.info).to.have.been.calledWith(`Canonical URL ${url} references itself`);
});

// FAILING TEST
it('should fail if the canonical URL does not point to itself', async () => {
const url = 'http://example.com';
const canonicalUrl = 'http://example.com/other-page';
Expand All @@ -295,27 +295,10 @@ describe('Canonical URL Tests', () => {
expect(result.checks).to.deep.include.members([{
check: 'canonical-self-referenced',
success: false,
explanation: 'The canonical URL should point to itself to indicate that it is the preferred version of the content.',
explanation: CANONICAL_CHECKS.CANONICAL_SELF_REFERENCED.explanation,
}]);
expect(log.info).to.have.been.calledWith(`Canonical URL ${canonicalUrl} does not reference itself`);
});

// FAILING TEST
it.skip('should handle an invalid canonical URL gracefully', async () => {
const url = 'http://example.com';
const invalidCanonicalUrl = 'http://[invalid-url]';
const html = `<html><head><link rel="canonical" href="${invalidCanonicalUrl}"></head><body></body></html>`;
nock(url).get('/').reply(200, html);

const result = await validateCanonicalTag(url, log);

expect(result.checks).to.deep.include({
check: 'canonical-tag-nonempty',
success: false,
explanation: 'The canonical tag is empty or contains an invalid URL. It should point to the preferred version of the page to avoid content duplication.',
});
expect(log.info).to.have.been.calledWith(`Invalid canonical URL found for page ${url}`);
});
});

describe('validateCanonicalRecursively', () => {
Expand All @@ -329,67 +312,7 @@ describe('Canonical URL Tests', () => {
expect(result).to.deep.include({ check: 'canonical-url-no-redirect', success: true });
});

// FAILING TEST
it.skip('should detect a redirect loop and handle it appropriately', async () => {
const canonicalUrl = 'http://example.com/page';
const visitedUrls = new Set([canonicalUrl]); // Simulate the URL already being visited

const result = await validateCanonicalRecursively(canonicalUrl, log, visitedUrls);

expect(result).to.deep.include({
check: 'canonical-url-no-redirect',
success: false,
explanation: 'The canonical URL should not redirect to another page or itself repeatedly.',
});
expect(log.info).to.have.been.calledWith(`Detected a redirect loop for canonical URL ${canonicalUrl}`);
});

// FAILING TEST
it.skip('should handle a 4xx error status correctly', async () => {
const canonicalUrl = 'http://example.com/notfound';
nock('http://example.com').get('/notfound').reply(404); // Simulate a 404 Not Found error

const result = await validateCanonicalRecursively(canonicalUrl, log);

expect(result).to.deep.include({
check: 'canonical-url-4xx',
success: false,
explanation: 'The canonical URL should not return a 4xx client error.',
});
expect(log.info).to.have.been.calledWith(`Canonical URL ${canonicalUrl} returned a 4xx error: 404`);
});

// FAILING TEST
it.skip('should handle a 5xx error status correctly', async () => {
const canonicalUrl = 'http://example.com/servererror';
nock('http://example.com').get('/servererror').reply(500); // Simulate a 500 Internal Server Error

const result = await validateCanonicalRecursively(canonicalUrl, log);

expect(result).to.deep.include({
check: 'canonical-url-5xx',
success: false,
explanation: 'The canonical URL should not return a 5xx server error.',
});
expect(log.info).to.have.been.calledWith(`Canonical URL ${canonicalUrl} returned a 5xx error: 500`);
});

// FAILING TEST
it.skip('should handle an unexpected status code correctly', async () => {
const canonicalUrl = 'http://example.com/unexpected';
nock('http://example.com').get('/unexpected').reply(418); // Simulate an unexpected status code (e.g., 418 I'm a teapot)

const result = await validateCanonicalRecursively(canonicalUrl, log);

expect(result).to.deep.include({
check: 'unexpected-status-code',
success: false,
explanation: 'The canonical URL returned an unexpected status code.',
});
expect(log.info).to.have.been.calledWith(`Unexpected status code 418 for canonical URL: ${canonicalUrl}`);
});

it.skip('should handle a fetch error correctly', async () => {
it('should handle a fetch error correctly', async () => {
const canonicalUrl = 'http://example.com/fetcherror';
nock('http://example.com').get('/fetcherror').replyWithError('Network error'); // Simulate a network error

Expand All @@ -398,7 +321,7 @@ describe('Canonical URL Tests', () => {
expect(result).to.deep.include({
check: 'canonical-url-fetch-error',
success: false,
explanation: 'There was an error fetching the canonical URL, which prevents validation of the canonical tag.',
explanation: CANONICAL_CHECKS.CANONICAL_URL_FETCH_ERROR.explanation,
});
expect(log.error).to.have.been.calledWith(`Error fetching canonical URL ${canonicalUrl}: Network error`);
});
Expand All @@ -416,8 +339,7 @@ describe('Canonical URL Tests', () => {
expect(log.info).to.have.been.called;
});

// FAILING TEST
it.skip('should return early and log a message when no top pages are found', async () => {
it('should return early and log a message when no top pages are found', async () => {
const baseURL = 'http://example.com';
const context = {
log,
Expand All @@ -434,62 +356,10 @@ describe('Canonical URL Tests', () => {
auditResult: {
check: 'top-pages',
success: false,
explanation: 'No top pages were found for the site. The audit cannot proceed without any pages to check.',
explanation: CANONICAL_CHECKS.TOPPAGES.explanation,
},
});
expect(log.info).to.have.been.calledWith('No top pages found, ending audit.');
});

// FAILING TEST
it.skip('should handle and log an error during the canonical audit', async () => {
const baseURL = 'http://example.com';
const context = {
log,
dataAccess: {
getTopPagesForSite: sinon.stub().rejects(new Error('Simulated error')), // Simulate an error
},
};
const site = { getId: () => 'testSiteId' };

const result = await canonicalAuditRunner(baseURL, context, site);

expect(result).to.deep.equal({
fullAuditRef: baseURL,
auditResult: {
error: 'Audit failed with error: Simulated error',
success: false,
},
});

expect(log.error).to.have.been.calledWith(
`Canonical Audit for site ${baseURL} failed with error: Simulated error`,
);
});

// FAILING TEST
it.skip('should handle and log an error during the canonical audit', async () => {
const baseURL = 'http://example.com';
const context = {
log,
dataAccess: {
getTopPagesForSite: sinon.stub().rejects(new Error('Simulated error')), // Simulate an error
},
};
const site = { getId: () => 'testSiteId' };

const result = await canonicalAuditRunner(baseURL, context, site);

expect(result).to.deep.equal({
fullAuditRef: baseURL,
auditResult: {
error: 'Audit failed with error: Simulated error',
success: false,
},
});

expect(log.error).to.have.been.calledWith(
`Canonical Audit for site ${baseURL} failed with error: Simulated error ${JSON.stringify(new Error('Simulated error'))}`,
);
});
});
});

0 comments on commit c7cd1ff

Please sign in to comment.