UNPKG

yoastseo-dep

Version:

Yoast clientside page analysis

420 lines (340 loc) 19.6 kB
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 ); } ); }