yoastseo-dep
Version:
Yoast clientside page analysis
420 lines (340 loc) • 19.6 kB
JavaScript
import getResults from "../getAssessorResults";
import Paper from "../../../src/values/Paper";
import KeyphraseDistributionAssessment from "../../../src/scoring/assessments/seo/KeyphraseDistributionAssessment";
import keyPhraseDistribution from "../../../src/languageProcessing/researches/keyphraseDistribution";
/* eslint-disable complexity */
/* eslint-disable max-statements */
/**
* Checks which assessment are available for an SEO assessor, given a certain Paper.
* @param {Assessor} assessor The SEO assessor.
* @param {boolean} isProductAssessor Whether this assessor is used for products.
* @returns {void}
*/
export function checkAssessmentAvailability( assessor, isProductAssessor = false ) {
/**
* Finds all assessments that have valid results for a given Paper.
* @param {Paper} paper The paper.
* @returns {string[]} The assessments with valid results.
*/
function assess( paper ) {
assessor.assess( paper );
return getResults( assessor.getValidResults() );
}
const isStoreBlog = assessor.type.startsWith( "storeBlog" );
const isCollection = assessor.type.startsWith( "collection" );
const isProduct = assessor.type.startsWith( "product" );
const isTaxonomy = assessor.type.startsWith( "taxonomy" );
if ( isProductAssessor && ! isStoreBlog ) {
// Add the Keyphrase distribution assessment to the assessor, which is available in these assessors in Shopify.
assessor._researcher.addResearch( "keyphraseDistribution", keyPhraseDistribution );
assessor.addAssessment( "keyphraseDistribution", new KeyphraseDistributionAssessment( {
urlTitle: isProduct ? "https://yoast.com/33" : "https://yoa.st/shopify30",
urlCallToAction: isProduct ? "https://yoast.com/34" : "https://yoa.st/shopify31",
} ) );
}
const defaultAssessments = [ "keyphraseLength", "metaDescriptionLength", "titleWidth", "textLength" ];
if ( isStoreBlog ) {
defaultAssessments.pop();
}
let requiresTextAssessments = [ "images", "externalLinks", "internalLinks" ];
if ( isCollection || isStoreBlog || isTaxonomy ) {
requiresTextAssessments = [];
}
if ( isProduct ) {
requiresTextAssessments = [ "images" ];
}
const requiresKeyphraseAssessments = [ "introductionKeyword" ];
if ( isStoreBlog ) {
requiresKeyphraseAssessments.pop();
}
const mostAssessments = [ ...defaultAssessments, ...requiresTextAssessments, ...requiresKeyphraseAssessments ];
it( "runs assessments without any specific requirements", function() {
const paper = new Paper( "" );
const assessments = assess( paper );
expect( assessments.sort() ).toEqual( defaultAssessments.sort() );
} );
it( "additionally runs assessments that only require a text", function() {
const paper = new Paper( "text" );
const assessments = assess( paper );
expect( assessments.sort() ).toEqual( [ ...defaultAssessments, ...requiresTextAssessments ].sort() );
} );
it( "additionally runs singleH1assessment if the text contains two H1s", function() {
const paper = new Paper( "<h1>First title</h1><h1>Second title</h1>" );
const assessments = assess( paper );
const expected = isStoreBlog ? defaultAssessments : [ ...defaultAssessments, ...requiresTextAssessments ].concat( "singleH1" );
expect( assessments.sort() ).toEqual( expected.sort() );
} );
it( "additionally runs assessments that only require a text and a keyword", function() {
const paper = new Paper( "text", { keyword: "keyword" } );
const assessments = assess( paper );
expect( assessments.sort() ).toEqual( mostAssessments.sort() );
} );
it( "additionally runs assessments that only require a keyword that contains function words only", function() {
const paper = new Paper( "", { keyword: "a" } );
const assessments = assess( paper );
expect( assessments.sort() ).toEqual( defaultAssessments.concat( "functionWordsInKeyphrase" ).sort() );
} );
it( "additionally runs assessments that require text and a keyword", function() {
const paper = new Paper( "text", { keyword: "keyword" } );
const assessments = assess( paper );
expect( assessments.sort() ).toEqual( mostAssessments.sort() );
} );
it( "additionally runs assessments that require a long enough text and a keyword and a synonym", function() {
const text = "a ".repeat( 200 );
const paper = new Paper( text, { keyword: "keyword", synonyms: "synonym" } );
const assessments = assess( paper );
const expected = isStoreBlog ? mostAssessments : mostAssessments.concat( "keyphraseDensity" );
expect( assessments.sort() ).toEqual( expected.sort() );
} );
it( "additionally runs assessments that require a text and a super-long slug with stop words", function() {
const paper = new Paper( "text",
{ slug: "a-sample-slug-a-sample-slug-a-sample-slug-a-sample-slug-a-sample-slug-a-sample-slug-a-sample-slug-a-sample-slug" } );
const assessments = assess( paper );
expect( assessments.sort() ).toEqual( [ ...defaultAssessments, ...requiresTextAssessments ].sort() );
} );
it( "additionally runs assessments that require a text, a slug and a keyword", function() {
const paper = new Paper( "text", { keyword: "keyword", slug: "sample-slug" } );
const assessments = assess( paper );
expect( assessments.sort() ).toEqual( mostAssessments.concat( "slugKeyword" ).sort() );
} );
// These specifications will additionally trigger the largest keyword distance assessment.
it( "additionally runs assessments that require a long enough text and two keyword occurrences", function() {
const paper = new Paper( "This is a keyword and a keyword. Lorem ipsum dolor sit amet, vim illum aeque" +
" constituam at. Id latine tritani alterum pro. Ei quod stet affert sed. Usu putent fabellas suavitate id." +
" Quo ut stet recusabo torquatos. Eum ridens possim expetenda te. Ex per putant comprehensam. At vel utinam" +
" cotidieque, at erat brute eum, velit percipit ius et. Has vidit accusata deterruisset ea, quod facete te" +
" vis. Vix ei duis dolor, id eum sonet fabulas. Id vix imperdiet efficiantur. Percipit probatus pertinax te" +
" sit. Putant intellegebat eu sit. Vix reque tation prompta id, ea quo labore viderer definiebas." +
" Oratio vocibus offendit an mei, est esse pericula liberavisse. Lorem ipsum dolor sit amet, vim illum aeque" +
" constituam at. Id latine tritani alterum pro. Ei quod stet affert sed. Usu putent fabellas suavitate id." +
" Quo ut stet recusabo torquatos. Eum ridens possim expetenda te. Ex per putant comprehensam. At vel utinam" +
" cotidieque, at erat brute eum, velit percipit ius et. Has vidit accusata deterruisset ea, quod facete te" +
" vis. Vix ei duis dolor, id eum sonet fabulas. Id vix imperdiet efficiantur. Percipit probatus pertinax te" +
" sit. Putant intellegebat eu sit. Vix reque tation prompta id, ea quo labore viderer definiebas." +
" Oratio vocibus offendit an mei, est esse pericula liberavisse.", { keyword: "keyword" } );
const assessments = assess( paper );
const keyphraseAssessments = isProductAssessor ? [ "keyphraseDistribution", "keyphraseDensity" ] : [ "keyphraseDensity" ];
const expected = isStoreBlog ? mostAssessments : [ ...mostAssessments, ...keyphraseAssessments ];
expect( assessments.sort() ).toEqual( expected.sort() );
} );
it( "additionally runs assessments that require a long enough text and one keyword occurrence and one synonym occurrence", function() {
const paper = new Paper( "This is a keyword. Lorem ipsum dolor sit amet, vim illum aeque" +
" constituam at. Id latine tritani alterum pro. Ei quod stet affert sed. Usu putent fabellas suavitate id." +
" Quo ut stet recusabo torquatos. Eum ridens possim expetenda te. Ex per putant comprehensam. At vel utinam" +
" cotidieque, at erat brute eum, velit percipit ius et. Has vidit accusata deterruisset ea, quod facete te" +
" vis. Vix ei duis dolor, id eum sonet fabulas. Id vix imperdiet efficiantur. Percipit probatus pertinax te" +
" sit. Putant intellegebat eu sit. Vix reque tation prompta id, ea quo labore viderer definiebas." +
" Oratio vocibus offendit an mei, est esse pericula liberavisse. Lorem ipsum dolor sit amet, vim illum aeque" +
" constituam at. Id latine tritani alterum pro. Ei quod stet affert sed. Usu putent fabellas suavitate id." +
" Quo ut stet recusabo torquatos. Eum ridens possim expetenda te. Ex per putant comprehensam. At vel utinam" +
" cotidieque, at erat brute eum, velit percipit ius et. Has vidit accusata deterruisset ea, quod facete te" +
" vis. Vix ei duis dolor, id eum sonet fabulas. Id vix imperdiet efficiantur. Percipit probatus pertinax te" +
" sit. Putant intellegebat eu sit. Vix reque tation prompta id, ea quo labore viderer definiebas synonym." +
" Oratio vocibus offendit an mei, est esse pericula liberavisse.", { keyword: "keyword", synonyms: "synonym" } );
const assessments = assess( paper );
const keyphraseAssessments = isProductAssessor ? [ "keyphraseDistribution", "keyphraseDensity" ] : [ "keyphraseDensity" ];
const expected = isStoreBlog ? mostAssessments : [ ...mostAssessments, ...keyphraseAssessments ];
expect( assessments.sort() ).toEqual( expected.sort() );
} );
}
/* eslint-enable complexity */
/* eslint-enable max-statements */
/**
* Checks the config overrides for a given SEO assessor.
* @param {Assessor} assessor The SEO assessor.
* @returns {void}
*/
export function checkConfigOverrides( assessor ) {
test( "MetaDescriptionLengthAssessment", () => {
const assessment = assessor.getAssessment( "metaDescriptionLength" );
expect( assessment ).toBeDefined();
expect( assessment._config ).toBeDefined();
expect( assessment._config.scores ).toBeDefined();
expect( assessment._config.scores.tooLong ).toBe( 3 );
expect( assessment._config.scores.tooShort ).toBe( 3 );
} );
test( "ImageKeyphrase", () => {
const assessment = assessor.getAssessment( "imageKeyphrase" );
expect( assessment ).toBeDefined();
expect( assessment._config ).toBeDefined();
expect( assessment._config.scores ).toBeDefined();
expect( assessment._config.scores.withAltNonKeyword ).toBe( 3 );
expect( assessment._config.scores.withAlt ).toBe( 3 );
expect( assessment._config.scores.noAlt ).toBe( 3 );
} );
test( "TextLengthAssessment", () => {
const assessment = assessor.getAssessment( "textLength" );
expect( assessment ).toBeDefined();
expect( assessment._config ).toBeDefined();
expect( assessment._config.recommendedMinimum ).toBe( 900 );
expect( assessment._config.slightlyBelowMinimum ).toBe( 400 );
expect( assessment._config.belowMinimum ).toBe( 300 );
expect( assessment._config.scores ).toBeDefined();
expect( assessment._config.scores.belowMinimum ).toBe( -20 );
expect( assessment._config.scores.farBelowMinimum ).toBe( -20 );
expect( assessment._config.cornerstoneContent ).toBeDefined();
expect( assessment._config.cornerstoneContent ).toBeTruthy();
} );
test( "OutboundLinksAssessment", () => {
const assessment = assessor.getAssessment( "externalLinks" );
expect( assessment ).toBeDefined();
expect( assessment._config ).toBeDefined();
expect( assessment._config.scores ).toBeDefined();
expect( assessment._config.scores.noLinks ).toBe( 3 );
} );
test( "PageTitleWidthAssessment", () => {
const assessment = assessor.getAssessment( "titleWidth" );
expect( assessment ).toBeDefined();
expect( assessment._config ).toBeDefined();
expect( assessment._config.scores ).toBeDefined();
expect( assessment._config.scores.widthTooShort ).toBe( 9 );
} );
test( "SlugKeywordAssessment", () => {
const assessment = assessor.getAssessment( "slugKeyword" );
expect( assessment ).toBeDefined();
expect( assessment._config ).toBeDefined();
expect( assessment._config.scores ).toBeDefined();
expect( assessment._config.scores.okay ).toBe( 3 );
} );
}
/**
* Checks the URLs for a given SEO assessor.
* @param {Assessor} assessor The SEO assessor.
* @param {boolean} isProductAssessor Whether this assessor is used for products.
* @returns {void}
*/
export function checkUrls( assessor, isProductAssessor = false ) {
/**
* Checks the URLs for a given assessment.
* @param {Assessment} assessment The assessment.
* @param {string} urlTitle The URL of the assessment title.
* @param {string} urlCallToAction The URL of the call-to-action.
* @returns {void}
*/
function checkAssessmentUrls( assessment, urlTitle, urlCallToAction ) {
if ( assessment ) {
expect( assessment._config ).toBeDefined();
expect( assessment._config.urlTitle ).toBe( `<a href='${urlTitle}' target='_blank'>` );
expect( assessment._config.urlCallToAction ).toBe( `<a href='${urlCallToAction}' target='_blank'>` );
}
}
const isTaxonomy = assessor.type.startsWith( "taxonomy" );
test( "IntroductionKeywordAssessment", () => {
const assessment = assessor.getAssessment( "introductionKeyword" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify8" : "https://yoa.st/33e";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify9" : "https://yoa.st/33f";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "KeyphraseLengthAssessment", () => {
const assessment = assessor.getAssessment( "keyphraseLength" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify10" : "https://yoa.st/33i";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify11" : "https://yoa.st/33j";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "keyphraseDensityAssessment", () => {
const assessment = assessor.getAssessment( "keyphraseDensity" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify12" : "https://yoa.st/33v";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify13" : "https://yoa.st/33w";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "MetaDescriptionKeywordAssessment", () => {
const assessment = assessor.getAssessment( "metaDescriptionKeyword" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify14" : "https://yoa.st/33k";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify15" : "https://yoa.st/33l";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "MetaDescriptionLengthAssessment", () => {
const assessment = assessor.getAssessment( "metaDescriptionLength" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify46" : "https://yoa.st/34d";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify47" : "https://yoa.st/34e";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "SubheadingsKeyword", () => {
const assessment = assessor.getAssessment( "subheadingsKeyword" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify16" : "https://yoa.st/33m";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify17" : "https://yoa.st/33n";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "TextCompetingLinksAssessment", () => {
const assessment = assessor.getAssessment( "textCompetingLinks" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify18" : "https://yoa.st/34l";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify19" : "https://yoa.st/34m";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "TextLengthAssessment", () => {
const assessment = assessor.getAssessment( "textLength" );
let urlTitle;
if ( isProductAssessor ) {
urlTitle = "https://yoa.st/shopify58";
} else {
urlTitle = isTaxonomy ? "https://yoa.st/34j" : "https://yoa.st/34n";
}
let urlCallToAction;
if ( isProductAssessor ) {
urlCallToAction = "https://yoa.st/shopify59";
} else {
urlCallToAction = isTaxonomy ? "https://yoa.st/34k" : "https://yoa.st/34o";
}
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "KeyphraseInSEOTitleAssessment", () => {
const assessment = assessor.getAssessment( "keyphraseInSEOTitle" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify24" : "https://yoa.st/33g";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify25" : "https://yoa.st/33h";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "PageTitleWidthAssessment", () => {
const assessment = assessor.getAssessment( "titleWidth" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify52" : "https://yoa.st/34h";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify53" : "https://yoa.st/34i";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "SlugKeywordAssessment", () => {
const assessment = assessor.getAssessment( "slugKeyword" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify26" : "https://yoa.st/33o";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify27" : "https://yoa.st/33p";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "FunctionWordsInKeyphrase", () => {
const assessment = assessor.getAssessment( "functionWordsInKeyphrase" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify50" : "https://yoa.st/functionwordskeyphrase-1";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify51" : "https://yoa.st/functionwordskeyphrase-2";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "SingleH1Assessment", () => {
const assessment = assessor.getAssessment( "singleH1" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify54" : "https://yoa.st/3a6";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify55" : "https://yoa.st/3a7";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "ImageCount", () => {
const assessment = assessor.getAssessment( "images" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify20" : "https://yoa.st/4f4";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify21" : "https://yoa.st/4f5";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "ImageKeyphrase", () => {
const assessment = assessor.getAssessment( "imageKeyphrase" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify22" : "https://yoa.st/4f7";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify23" : "https://yoa.st/4f6";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "KeyphraseDistribution", () => {
const assessment = assessor.getAssessment( "keyphraseDistribution" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify30" : "https://yoa.st/33q";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify31" : "https://yoa.st/33u";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "OutboundLinks", () => {
const assessment = assessor.getAssessment( "externalLinks" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify62" : "https://yoa.st/34f";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify63" : "https://yoa.st/34g";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
test( "InternalLinksAssessment", () => {
const assessment = assessor.getAssessment( "internalLinks" );
const urlTitle = isProductAssessor ? "https://yoa.st/shopify60" : "https://yoa.st/33z";
const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify61" : "https://yoa.st/34a";
checkAssessmentUrls( assessment, urlTitle, urlCallToAction );
} );
}