Skip to content
This repository has been archived by the owner on Oct 4, 2022. It is now read-only.

P2 807 variation picker validation #1142

Merged
merged 23 commits into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a453363
first steps
increddibelly Mar 30, 2021
bc19f27
added comment
increddibelly Mar 30, 2021
a91b104
make the VariationPicker validation verify that a block is selected
increddibelly Apr 2, 2021
5ad724e
removed unused imports
increddibelly Apr 2, 2021
6b3f96a
Merge remote-tracking branch 'origin/develop' into P2-807-VariationPi…
increddibelly Apr 6, 2021
f947f2e
simplified parent / child relation in validation
increddibelly Apr 6, 2021
6b9e27c
Updated tests for BlockInstruction.
hansjovis Apr 8, 2021
539a51b
Merge remote-tracking branch 'origin/develop' into P2-807-VariationPi…
hansjovis Apr 8, 2021
7b17aeb
cleanup unit test
increddibelly Apr 8, 2021
14cfa8e
fixed variationpicker validation naming
increddibelly Apr 9, 2021
5b27fa9
Merge remote-tracking branch 'origin/develop' into P2-807-VariationPi…
increddibelly Apr 9, 2021
adf1c54
Don't pass the default value of an optional parameter
johannadevos Apr 12, 2021
c916123
Improve CS
johannadevos Apr 12, 2021
1ad79e6
allow variationpickers to be recommended blocks
increddibelly Apr 9, 2021
b067b89
Expand documentation
increddibelly Apr 12, 2021
ffd6e9e
Merge remote-tracking branch 'origin/develop' into P2-807-VariationPi…
increddibelly Apr 12, 2021
b4fe30c
simplified validation by passing the presence parameter
increddibelly Apr 12, 2021
4ffbe6e
remove unused import
increddibelly Apr 13, 2021
6e08cd3
Merge remote-tracking branch 'origin/develop' into P2-807-VariationPi…
increddibelly Apr 13, 2021
bdd1360
updated validation to explicitly mention unpicked variations
increddibelly Apr 13, 2021
4634389
fix typo
increddibelly Apr 13, 2021
e0501ad
Merge remote-tracking branch 'origin/develop' into P2-807-VariationPi…
hansjovis Apr 13, 2021
a76a4f6
Used backticks instead of quotation marks in test.
hansjovis Apr 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
simplified validation by passing the presence parameter
renamed validation result for consistency
improved validation for VariationPicker
  • Loading branch information
increddibelly committed Apr 12, 2021
commit b4fe30cb809ac53c0a8d759b8dfa22a4e09375f7
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export enum BlockValidation {
/** This block (OR some of its innerblocks) have a problem. The particular problem must be specified in BlockValidationResult.issues */
Invalid = 300,
/** This block has required attributes, but these attributes are missing or empty. */
MissingAttribute = 301,
MissingRequiredAttribute = 301,
/** This block is defined to require a particular inner block, but that block doesn't exist. */
MissingRequiredBlock = 302,
/** There may be only one of this type of block, but we found more than one. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ export class BlockValidationResult {
*
* @param blockInstance The block instance.
* @param [name] Optional name.
* @param blockPresence The block type.
* @param [blockPresence] The block type.
*
* @constructor
*/
static MissingAttribute( blockInstance: BlockInstance, name?: string, blockPresence?: BlockPresence ) {
const blockValidation: BlockValidation = ( blockPresence === BlockPresence.Required )
? BlockValidation.MissingAttribute : BlockValidation.MissingRecommendedAttribute;
? BlockValidation.MissingRequiredAttribute : BlockValidation.MissingRecommendedAttribute;

return new BlockValidationResult(
blockInstance.clientId,
Expand All @@ -82,18 +82,23 @@ export class BlockValidationResult {
}

/**
* Named constructor for a 'missing required block' validation result.
* Named constructor for a 'missing recommended / required block' validation result.
*
* @param name The name of the missing block.
* @param [blockPresence] The block presence.
*
* @constructor
*/
static MissingRequiredBlock( name: string ) {
static MissingBlock( name: string, blockPresence?: BlockPresence ) {
if ( blockPresence === BlockPresence.Recommended ) {
return BlockValidationResult.MissingRecommendedBlock( name );
}

return new BlockValidationResult(
null,
name,
BlockValidation.MissingRequiredBlock,
BlockPresence.Required,
blockPresence || BlockPresence.Unknown,
sprintf(
/* Translators: %1$s expands to the block name. */
__( "The '%1$s' block is required but missing.", "yoast-schema-blocks" ),
Expand All @@ -109,7 +114,7 @@ export class BlockValidationResult {
*
* @constructor
*/
static MissingRecommendedBlock( name: string ) {
private static MissingRecommendedBlock( name: string ) {
return new BlockValidationResult(
null,
name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function getValidationResult( clientId: string ): BlockValidationResult | null {
*/
function someRequiredBlocksNotCompleted( issues: BlockValidationResult[] ) {
return issues.some( issue => issue.result === BlockValidation.MissingRequiredBlock ||
issue.result === BlockValidation.MissingAttribute );
issue.result === BlockValidation.MissingRequiredAttribute );
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,21 @@ import { getHumanReadableBlockName } from "../BlockHelper";
* Finds all blocks that should/could be in the inner blocks, but aren't.
*
* @param existingBlocks The actual array of all inner blocks.
* @param allBlocks All of the blocks that should occur (required), or could occur (recommended) in the inner blocks.
* @param wantedBlocks All of the blocks that should occur (required), or could occur (recommended) in the inner blocks.
* @param blockPresence The block presence.
*
* @returns {BlockValidationResult[]} The names of blocks that should/could occur but don't, with reason 'MissingBlock'.
*/
function findMissingBlocks( existingBlocks: BlockInstance[], allBlocks: RequiredBlock[] | RecommendedBlock[],
function findMissingBlocks( existingBlocks: BlockInstance[], wantedBlocks: RequiredBlock[] | RecommendedBlock[],
blockPresence: BlockPresence ): BlockValidationResult[] {
const missingBlocks = allBlocks.filter( block => {
const missingBlocks = wantedBlocks.filter( block => {
// If, in the existing blocks, there are not any blocks with the name of block, that block is missing.
return ! existingBlocks.some( existingBlock => existingBlock.name === block.name );
} );

// Return a BlockValidationResult for a required block.
if ( blockPresence === BlockPresence.Required ) {
// These blocks should've existed, but they don't.
return missingBlocks.map( missingBlock =>
BlockValidationResult.MissingRequiredBlock( getHumanReadableBlockName( missingBlock.name ) ),
);
}

// Return a BlockValidationResult for a recommended block.
// These blocks should've existed, but they don't.
return missingBlocks.map( missingBlock =>
BlockValidationResult.MissingRecommendedBlock( getHumanReadableBlockName( missingBlock.name ) ),
BlockValidationResult.MissingBlock( getHumanReadableBlockName( missingBlock.name ), blockPresence ),
);
}

Expand Down
6 changes: 4 additions & 2 deletions packages/schema-blocks/src/instructions/blocks/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Title extends VariableTagRichText {
multiline: boolean;
label: string;
value: string;
required?: boolean;
};

/**
Expand All @@ -44,7 +45,7 @@ class Title extends VariableTagRichText {
* @returns Whether the block is completed.
*/
private isCompleted( blockInstance: BlockInstance ): boolean {
return attributeNotEmpty( blockInstance, this.options.name ) && attributeExists( blockInstance, this.options.name );
return attributeExists( blockInstance, this.options.name ) && attributeNotEmpty( blockInstance, this.options.name );
}

/**
Expand All @@ -61,7 +62,8 @@ class Title extends VariableTagRichText {
const postTitle: string = post.title;

if ( ! this.isCompleted( blockInstance ) ) {
return BlockValidationResult.MissingAttribute( blockInstance, this.options.name );
const presence = this.options.required === true ? BlockPresence.Required : BlockPresence.Recommended;
return BlockValidationResult.MissingAttribute( blockInstance, this.constructor.name, presence );
}

if ( blockTitle.toLocaleLowerCase() === postTitle.toLocaleLowerCase() ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import BlockLeaf from "../../core/blocks/BlockLeaf";
import { BlockInstance } from "@wordpress/blocks";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { createElement } from "@wordpress/element";
import { BlockPresence, BlockValidationResult } from "../../core/validation";
import { BlockPresence, BlockValidation, BlockValidationResult } from "../../core/validation";
import VariationPickerPresenter from "../../functions/presenters/VariationPickerPresenter";

/**
Expand Down Expand Up @@ -55,13 +55,13 @@ class VariationPicker extends BlockInstruction {
* @returns {BlockValidationResult} The validation result.
*/
validate( blockInstance: BlockInstance ): BlockValidationResult {
const required: BlockPresence = this.options.required ? BlockPresence.Required : BlockPresence.Recommended;
const presence: BlockPresence = this.options.required ? BlockPresence.Required : BlockPresence.Recommended;

if ( includesAVariation( blockInstance ) ) {
return BlockValidationResult.Valid( blockInstance, this.constructor.name, required );
return BlockValidationResult.Valid( blockInstance, this.constructor.name, presence );
}

return BlockValidationResult.MissingAttribute( blockInstance, this.constructor.name, required );
return BlockValidationResult.MissingBlock( this.constructor.name, presence );
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ describe( "The BlockInstruction class", () => {

const result = blockInstruction.validate( blockInstance );
expect( result.name ).toEqual( "TestBlockInstruction" );
expect( result.result ).toEqual( BlockValidation.MissingAttribute );
expect( result.result ).toEqual( BlockValidation.MissingRequiredAttribute );
expect( result.issues.length ).toEqual( 1 );

const issue = result.issues[ 0 ];
expect( issue.name ).toEqual( "TestBlockInstruction" );
expect( issue.result ).toEqual( BlockValidation.MissingAttribute );
expect( issue.result ).toEqual( BlockValidation.MissingRequiredAttribute );
} );

it( "considers a required attribute to be invalid if it is empty", () => {
Expand All @@ -123,12 +123,12 @@ describe( "The BlockInstruction class", () => {

const result = blockInstruction.validate( blockInstance );
expect( result.name ).toEqual( "TestBlockInstruction" );
expect( result.result ).toEqual( BlockValidation.MissingAttribute );
expect( result.result ).toEqual( BlockValidation.MissingRequiredAttribute );
expect( result.issues.length ).toEqual( 1 );

const issue = result.issues[ 0 ];
expect( issue.name ).toEqual( "TestBlockInstruction" );
expect( issue.result ).toEqual( BlockValidation.MissingAttribute );
expect( issue.result ).toEqual( BlockValidation.MissingRequiredAttribute );
} );
} );
} );
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BlockValidation, BlockValidationResult } from "../../../src/core/validation";
import getWarnings, { createAnalysisMessages } from "../../../src/functions/presenters/SidebarWarningPresenter";
import { BlockPresence } from "../../../src/core/validation/BlockValidationResult";
import { BlockInstance } from "@wordpress/blocks";

const validations: Record<string, BlockValidationResult> = {};

Expand Down Expand Up @@ -49,7 +50,7 @@ describe( "The SidebarWarningPresenter ", () => {
it( "creates a footer message when some required blocks have missing attributes.", () => {
const testcase = new BlockValidationResult( "1", "mijnblock", BlockValidation.Invalid, BlockPresence.Unknown );
testcase.issues.push(
new BlockValidationResult( null, "missingblockattribute", BlockValidation.MissingAttribute, BlockPresence.Unknown )
new BlockValidationResult( null, "missingblockattribute", BlockValidation.MissingRequiredAttribute, BlockPresence.Unknown ),
);

const result = createAnalysisMessages( testcase );
Expand All @@ -65,7 +66,7 @@ describe( "The SidebarWarningPresenter ", () => {

it( "creates warning messages for missing required blocks, with a footer message.", () => {
const testcase = new BlockValidationResult( "1", "mijnblock", BlockValidation.Invalid, BlockPresence.Required );
testcase.issues.push( BlockValidationResult.MissingRequiredBlock( "missingblock" ) );
testcase.issues.push( BlockValidationResult.MissingBlock( "missingblock", BlockPresence.Required ) );

const result = createAnalysisMessages( testcase );

Expand All @@ -81,14 +82,15 @@ describe( "The SidebarWarningPresenter ", () => {
},
);
} );
it( "creates a warning for missing recommended blocks, but when all the required blocks are present " +

it( "creates a warning for missing recommended blocks, but when no required blocks are missing, " +
"the conclusion should still be green.", () => {
const testcase = new BlockValidationResult( "1", "mijnblock", BlockValidation.Invalid, BlockPresence.Recommended );
testcase.issues.push(
BlockValidationResult.MissingRecommendedBlock( "missing recommended block" ),
BlockValidationResult.MissingBlock( "missing recommended block", BlockPresence.Recommended ),
);
testcase.issues.push(
BlockValidationResult.MissingRecommendedBlock( "missing recommended block 2" ),
BlockValidationResult.MissingBlock( "missing recommended block 2", BlockPresence.Recommended ),
);

const result = createAnalysisMessages( testcase );
Expand All @@ -107,6 +109,29 @@ describe( "The SidebarWarningPresenter ", () => {
color: "green",
} );
} );

it( "creates a warning for missing recommended blocks, but when all required blocks are valid, " +
"the conclusion should still be green.", () => {
const testcase = new BlockValidationResult( "1", "mijnblock", BlockValidation.Invalid, BlockPresence.Recommended );
testcase.issues.push(
BlockValidationResult.MissingBlock( "missing recommended block", BlockPresence.Recommended ),
);
testcase.issues.push(
BlockValidationResult.Valid( { name: "valid required block 1", clientId: "1" } as unknown as BlockInstance, BlockPresence.Required ),
);

const result = createAnalysisMessages( testcase );

expect( result.length ).toEqual( 2 );
expect( result[ 0 ] ).toEqual( {
text: "The 'missing recommended block' block is recommended but missing.",
color: "orange",
} );
expect( result[ 1 ] ).toEqual( {
text: "Good job! All required blocks have been completed.",
color: "green",
} );
} );
} );

describe( "The getWarnings method ", () => {
Expand All @@ -117,7 +142,7 @@ describe( "The SidebarWarningPresenter ", () => {

expect( result ).toEqual( [ {
text: "Good job! All required blocks have been completed.",
color: "green"
color: "green",
} ] );
} );

Expand All @@ -138,7 +163,7 @@ describe( "The SidebarWarningPresenter ", () => {

it( "creates a warning for a required block with validation problems.", () => {
const testcase = new BlockValidationResult( "1", "myBlock", BlockValidation.Invalid, BlockPresence.Required );
testcase.issues.push( BlockValidationResult.MissingRequiredBlock( "innerblock1" ) );
testcase.issues.push( BlockValidationResult.MissingBlock( "innerblock1", BlockPresence.Required ) );
validations[ "1" ] = testcase;

const result = getWarnings( "1" );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const createBlockValidationResultTestArrangement = [
{ name: "missingrequiredblock", reason: BlockValidation.MissingRequiredBlock },
{ name: "missingrecommendedblock", reason: BlockValidation.MissingRecommendedBlock },
{ name: "redundantblock", reason: BlockValidation.TooMany },
{ name: "missingattributeblock", reason: BlockValidation.MissingAttribute },
{ name: "missingattributeblock", reason: BlockValidation.MissingRequiredAttribute },
{ name: "validblock", reason: BlockValidation.Valid },
{ name: "invalidblock", reason: BlockValidation.Invalid },
{ name: "unknown", reason: BlockValidation.Unknown },
Expand Down Expand Up @@ -251,7 +251,7 @@ describe( "The findSelfInvalidatedBlocks function", () => {
} as BlockInstance;

mockDefinition( "validBlock1", "validBlock", BlockValidation.Valid );
mockDefinition( "missingattributeblock1", "missingattributeblock", BlockValidation.MissingAttribute );
mockDefinition( "missingattributeblock1", "missingattributeblock", BlockValidation.MissingRequiredAttribute );

// Act.
const result: BlockValidationResult[] = innerBlocksValid.validateInnerblockTree( testBlock );
Expand All @@ -266,7 +266,7 @@ describe( "The findSelfInvalidatedBlocks function", () => {
const missingattributeblock = result.find( x => x.clientId === "missingattributeblock1" );
expect( missingattributeblock.name ).toEqual( "missingattributeblock" );
expect( missingattributeblock.result ).toEqual( BlockValidation.Invalid );
expect( missingattributeblock.issues[ 0 ].result ).toEqual( BlockValidation.MissingAttribute );
expect( missingattributeblock.issues[ 0 ].result ).toEqual( BlockValidation.MissingRequiredAttribute );
} );
} );

Expand Down