diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml index 638de1de0..f114cae1e 100644 --- a/.github/workflows/cypress-tests.yml +++ b/.github/workflows/cypress-tests.yml @@ -20,6 +20,10 @@ jobs: cypress_local: name: Cypress - Local runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + testGroup: ['@slow', '-@slow'] steps: - name: Checkout @@ -51,7 +55,7 @@ jobs: run: npm run cypress:setup - name: Test - run: npm run cypress:run + run: npm run cypress:run -- --env grepTags=${{ matrix.testGroup }} - name: Make artifacts available uses: actions/upload-artifact@v3 @@ -71,6 +75,10 @@ jobs: cypress_epio: name: Cypress - EP.io runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + testGroup: ['@slow', '-@slow'] steps: - name: Checkout @@ -104,7 +112,7 @@ jobs: run: npm run cypress:setup -- --ep-host=${{ secrets.EPIO_HOST }} --es-shield='${{ secrets.EPIO_SHIELD }}' --ep-index-prefix=${{ secrets.EPIO_INDEX_PREFIX }} - name: Test - run: npm run cypress:run + run: npm run cypress:run -- --env grepTags=${{ matrix.testGroup }} - name: Make artifacts available uses: actions/upload-artifact@v3 diff --git a/assets/js/blocks/facets/meta-range/block.json b/assets/js/blocks/facets/meta-range/block.json new file mode 100644 index 000000000..da7145621 --- /dev/null +++ b/assets/js/blocks/facets/meta-range/block.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "title": "Facet by Meta Range (ElasticPress)", + "textdomain": "elasticpress", + "name": "elasticpress/facet-meta-range", + "icon": "feedback", + "category": "widgets", + "attributes": { + "facet": { + "type": "string", + "default": "" + } + }, + "supports": { + "html": false + }, + "editorScript": "ep-facets-meta-range-block-script", + "style": "file:/../../../../../dist/css/facets-styles.css" +} \ No newline at end of file diff --git a/assets/js/blocks/facets/meta-range/edit.js b/assets/js/blocks/facets/meta-range/edit.js new file mode 100644 index 000000000..1dbc42d8e --- /dev/null +++ b/assets/js/blocks/facets/meta-range/edit.js @@ -0,0 +1,81 @@ +/* global facetMetaBlock */ + +import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; +import { PanelBody, Spinner, Placeholder, SelectControl } from '@wordpress/components'; +import { + Fragment, + useEffect, + useState, + useCallback, + createInterpolateElement, +} from '@wordpress/element'; +import apiFetch from '@wordpress/api-fetch'; +import { __ } from '@wordpress/i18n'; + +const FacetBlockEdit = (props) => { + const { attributes, setAttributes } = props; + const [metaKeys, setMetaKeys] = useState([]); + const [preview, setPreview] = useState(''); + const [loading, setLoading] = useState(false); + const { facet, min, max } = attributes; + + const blockProps = useBlockProps(); + + const load = useCallback(async () => { + const metaKeys = await apiFetch({ + path: '/elasticpress/v1/facets/meta-range/keys', + }); + setMetaKeys(metaKeys); + }, [setMetaKeys]); + + useEffect(load, [load]); + + useEffect(() => { + setLoading(true); + const params = new URLSearchParams({ facet }); + apiFetch({ + path: `/elasticpress/v1/facets/meta-range/block-preview?${params}`, + }) + .then((preview) => setPreview(preview)) + .finally(() => setLoading(false)); + }, [facet, min, max]); + + return ( + + + + sync your content', + 'elasticpress', + ), + // eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label + { a: }, + )} + value={facet} + options={[ + ...metaKeys.map((metaKey) => ({ + label: metaKey, + value: metaKey, + })), + ]} + onChange={(value) => setAttributes({ facet: value })} + /> + + + +
+ {loading && ( + + + + )} + {/* eslint-disable-next-line react/no-danger */} + {!loading &&
} +
+ + ); +}; +export default FacetBlockEdit; diff --git a/assets/js/blocks/facets/meta-range/index.js b/assets/js/blocks/facets/meta-range/index.js new file mode 100644 index 000000000..f2e7dac9c --- /dev/null +++ b/assets/js/blocks/facets/meta-range/index.js @@ -0,0 +1,15 @@ +/** + * WordPress dependencies. + */ +import { registerBlockType } from '@wordpress/blocks'; + +/** + * Internal dependencies. + */ +import edit from './edit'; +import block from './block.json'; + +registerBlockType(block, { + edit, + save: () => {}, +}); diff --git a/bin/setup-cypress-env.sh b/bin/setup-cypress-env.sh index de5d5364a..b688959b5 100755 --- a/bin/setup-cypress-env.sh +++ b/bin/setup-cypress-env.sh @@ -43,6 +43,9 @@ if [ -z $EP_HOST ]; then if [ "$(uname | tr '[:upper:]' '[:lower:]')" = "darwin" ]; then echo "Running tests on $(uname)" EP_HOST="http://host.docker.internal:8890/" + elif grep -qi microsoft /proc/version; then + echo "Running tests on Windows" + EP_HOST="http://host.docker.internal:8890/" else echo "Running tests on $(uname)" # 172.17.0.1 is the IP Address of host when using Linux diff --git a/includes/classes/Feature/Facets/FacetType.php b/includes/classes/Feature/Facets/FacetType.php index 36aca5814..dad760d37 100644 --- a/includes/classes/Feature/Facets/FacetType.php +++ b/includes/classes/Feature/Facets/FacetType.php @@ -53,4 +53,40 @@ public function get_sanitize_callback() : string { return apply_filters( 'ep_facet_default_sanitize_callback', 'sanitize_text_field' ); } + /** + * Format selected values. + * + * @since 4.5.0 + * @param string $facet Facet name + * @param mixed $value Facet value + * @param array $filters Selected filters + * @return array + */ + public function format_selected( string $facet, $value, array $filters ) { + $terms = explode( ',', trim( $value, ',' ) ); + $filters[ $this->get_filter_type() ][ $facet ] = [ + 'terms' => array_fill_keys( array_map( $this->get_sanitize_callback(), $terms ), true ), + ]; + return $filters; + } + + /** + * Add selected filters to the query string. + * + * @since 4.5.0 + * @param array $query_params Existent query parameters + * @param array $filters Selected filters + * @return array + */ + public function add_query_params( array $query_params, array $filters ) : array { + $selected = $filters[ $this->get_filter_type() ]; + + foreach ( $selected as $facet => $filter ) { + if ( ! empty( $filter['terms'] ) ) { + $query_params[ $this->get_filter_name() . $facet ] = implode( ',', array_keys( $filter['terms'] ) ); + } + } + + return $query_params; + } } diff --git a/includes/classes/Feature/Facets/Facets.php b/includes/classes/Feature/Facets/Facets.php index 84d3f105b..24159b122 100644 --- a/includes/classes/Feature/Facets/Facets.php +++ b/includes/classes/Feature/Facets/Facets.php @@ -351,12 +351,17 @@ public function get_aggs( $response, $query, $query_args, $query_object ) { continue; } - if ( ! is_array( $agg ) || empty( $agg['buckets'] ) ) { + if ( ! is_array( $agg ) || ( empty( $agg['buckets'] ) && empty( $agg['value'] ) ) ) { continue; } $GLOBALS['ep_facet_aggs'][ $key ] = []; + if ( ! empty( $agg['value'] ) ) { + $GLOBALS['ep_facet_aggs'][ $key ] = $agg['value']; + continue; + } + foreach ( $agg['buckets'] as $bucket ) { $GLOBALS['ep_facet_aggs'][ $key ][ $bucket['key'] ] = $bucket['doc_count']; } @@ -374,29 +379,20 @@ public function get_aggs( $response, $query, $query_args, $query_object ) { public function get_selected() { $allowed_args = $this->get_allowed_query_args(); - $filters = []; - $filter_names = []; - $sanitize_callbacks = []; + $filters = []; + $filter_names = []; foreach ( $this->types as $type_obj ) { - $filter_type = $type_obj->get_filter_type(); - - $filters[ $filter_type ] = []; - $filter_names[ $filter_type ] = $type_obj->get_filter_name(); - $sanitize_callbacks[ $filter_type ] = $type_obj->get_sanitize_callback(); + $filter_names[ $type_obj->get_filter_name() ] = $type_obj; } foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification $key = sanitize_key( $key ); - foreach ( $filter_names as $filter_type => $filter_name ) { + foreach ( $filter_names as $filter_name => $type_obj ) { if ( 0 === strpos( $key, $filter_name ) ) { - $facet = str_replace( $filter_name, '', $key ); - $sanitize_callback = $sanitize_callbacks[ $filter_type ]; - $terms = explode( ',', trim( $value, ',' ) ); + $facet = str_replace( $filter_name, '', $key ); - $filters[ $filter_type ][ $facet ] = array( - 'terms' => array_fill_keys( array_map( $sanitize_callback, $terms ), true ), - ); + $filters = $type_obj->format_selected( $facet, $value, $filters ); } } @@ -416,20 +412,13 @@ public function get_selected() { * @return string */ public function build_query_url( $filters ) { - $query_param = array(); + $query_params = array(); foreach ( $this->types as $type_obj ) { - $filter_type = $type_obj->get_filter_type(); - - if ( ! empty( $filters[ $filter_type ] ) ) { - $type_filters = $filters[ $filter_type ]; - - foreach ( $type_filters as $facet => $filter ) { - if ( ! empty( $filter['terms'] ) ) { - $query_param[ $type_obj->get_filter_name() . $facet ] = implode( ',', array_keys( $filter['terms'] ) ); - } - } + if ( empty( $filters[ $type_obj->get_filter_type() ] ) ) { + continue; } + $query_params = $type_obj->add_query_params( $query_params, $filters ); } $feature = Features::factory()->get_registered_feature( 'facets' ); @@ -438,22 +427,22 @@ public function build_query_url( $filters ) { if ( ! empty( $filters ) ) { foreach ( $filters as $filter => $value ) { if ( in_array( $filter, $allowed_args, true ) ) { - $query_param[ $filter ] = $value; + $query_params[ $filter ] = $value; } } } - $query_string = build_query( $query_param ); + $query_string = build_query( $query_params ); /** * Filter facet query string * * @hook ep_facet_query_string * @param {string} $query_string Current query string - * @param {array} $query_param Query parameters + * @param {array} $query_params Query parameters * @return {string} New query string */ - $query_string = apply_filters( 'ep_facet_query_string', $query_string, $query_param ); + $query_string = apply_filters( 'ep_facet_query_string', $query_string, $query_params ); $url = $_SERVER['REQUEST_URI']; $pagination = strpos( $url, '/page' ); diff --git a/includes/classes/Feature/Facets/Types/Meta/FacetType.php b/includes/classes/Feature/Facets/Types/Meta/FacetType.php index ed60ee0ce..f6ac0a051 100644 --- a/includes/classes/Feature/Facets/Types/Meta/FacetType.php +++ b/includes/classes/Feature/Facets/Types/Meta/FacetType.php @@ -251,7 +251,10 @@ public function get_facets_meta_fields() { continue; } - if ( false === strpos( $instance['content'], 'elasticpress/facet-meta' ) ) { + if ( + false !== strpos( $instance['content'], 'elasticpress/facet-meta-range' ) + || false === strpos( $instance['content'], 'elasticpress/facet-meta' ) + ) { continue; } diff --git a/includes/classes/Feature/Facets/Types/MetaRange/Block.php b/includes/classes/Feature/Facets/Types/MetaRange/Block.php new file mode 100644 index 000000000..0c2c88071 --- /dev/null +++ b/includes/classes/Feature/Facets/Types/MetaRange/Block.php @@ -0,0 +1,218 @@ + [ $this, 'render_block' ], + ] + ); + + wp_localize_script( 'ep-facets-meta-range-block-script', 'facetMetaBlock', [ 'syncUrl' => Utils\get_sync_url() ] ); + } + + + /** + * Setup REST endpoints for the feature. + */ + public function setup_endpoints() { + register_rest_route( + 'elasticpress/v1', + 'facets/meta-range/keys', + [ + 'methods' => 'GET', + 'permission_callback' => [ $this, 'check_facets_meta_rest_permission' ], + 'callback' => [ $this, 'get_rest_registered_metakeys' ], + ] + ); + register_rest_route( + 'elasticpress/v1', + 'facets/meta-range/block-preview', + [ + 'methods' => 'GET', + 'permission_callback' => [ $this, 'check_facets_meta_rest_permission' ], + 'callback' => [ $this, 'render_block_preview' ], + 'args' => [ + 'facet' => [ + 'sanitize_callback' => 'sanitize_text_field', + ], + ], + + ] + ); + } + + /** + * Check permissions of the /facets/taxonomies REST endpoint. + * + * @return WP_Error|true + */ + public function check_facets_meta_rest_permission() { + if ( ! current_user_can( 'edit_theme_options' ) ) { + return new \WP_Error( 'ep_rest_forbidden', esc_html__( 'Sorry, you cannot view this resource.', 'elasticpress' ), array( 'status' => 401 ) ); + } + + return true; + } + + /** + * Render the block. + * + * @param array $attributes Block attributes. + */ + public function render_block( $attributes ) { + $attributes = $this->parse_attributes( $attributes ); + + /** This filter is documented in includes/classes/Feature/Facets/Types/Taxonomy/Block.php */ + $renderer_class = apply_filters( 'ep_facet_renderer_class', __NAMESPACE__ . '\Renderer', 'meta-range', 'block', $attributes ); + $renderer = new $renderer_class(); + + ob_start(); + ?> +
+ render( [], $attributes ); ?> +
+ get_registered_feature( 'search' ); + + $attributes = $this->parse_attributes( + [ + 'facet' => $request->get_param( 'facet' ), + 'is_preview' => true, + ] + ); + + add_filter( + 'ep_facet_meta_fields', + function ( $meta_fields ) use ( $attributes ) { + $meta_fields = [ $attributes['facet'] ]; + return $meta_fields; + } + ); + + $wp_query = new \WP_Query( + [ + 'post_type' => $search->get_searchable_post_types(), + 'per_page' => 1, + ] + ); + + /** This filter is documented in includes/classes/Feature/Facets/Types/Taxonomy/Block.php */ + $renderer_class = apply_filters( 'ep_facet_renderer_class', __NAMESPACE__ . '\Renderer', 'meta-block', 'block', $attributes ); + $renderer = new $renderer_class(); + + ob_start(); + $renderer->render( [], $attributes ); + $block_content = ob_get_clean(); + + if ( empty( $block_content ) ) { + return sprintf( + /* translators: Meta field name */ + esc_html__( 'Preview for %s not available', 'elasticpress' ), + esc_html( $request->get_param( 'facet' ) ) + ); + } + + $block_content = preg_replace( '/href="(.*?)"/', 'href="#"', $block_content ); + return '
' . $block_content . '
'; + } + + /** + * Return an array of registered meta keys. + * + * @return array + */ + public function get_rest_registered_metakeys() { + $post_indexable = \ElasticPress\Indexables::factory()->get( 'post' ); + + try { + $meta_keys = $post_indexable->get_distinct_meta_field_keys(); + } catch ( \Throwable $th ) { + $meta_keys = []; + } + + return $meta_keys; + } + + /** + * Utilitary method to set default attributes. + * + * @param array $attributes Attributes passed + * @return array + */ + protected function parse_attributes( $attributes ) { + $attributes = wp_parse_args( + $attributes, + [ + 'facet' => '', + 'is_preview' => false, + ] + ); + if ( empty( $attributes['facet'] ) ) { + $registered_metakeys = $this->get_rest_registered_metakeys(); + if ( ! empty( $registered_metakeys ) ) { + $attributes['facet'] = reset( $registered_metakeys ); + } + } + return $attributes; + } +} diff --git a/includes/classes/Feature/Facets/Types/MetaRange/FacetType.php b/includes/classes/Feature/Facets/Types/MetaRange/FacetType.php new file mode 100644 index 000000000..39e2a695c --- /dev/null +++ b/includes/classes/Feature/Facets/Types/MetaRange/FacetType.php @@ -0,0 +1,225 @@ +block = new Block(); + $this->block->setup(); + } + + /** + * Get the facet filter name. + * + * @return string The filter name. + */ + public function get_filter_name() : string { + /** + * Filter the facet filter name that's added to the URL + * + * @hook ep_facet_meta_range_filter_name + * @since 4.5.0 + * @param {string} Facet filter name + * @return {string} New facet filter name + */ + return apply_filters( 'ep_facet_meta_range_filter_name', 'ep_meta_range_filter_' ); + } + + /** + * Get the facet filter type. + * + * @return string The filter name. + */ + public function get_filter_type() : string { + /** + * Filter the facet filter type. Used by the Facet feature to organize filters. + * + * @hook ep_facet_meta_range_filter_type + * @since 4.5.0 + * @param {string} Facet filter type + * @return {string} New facet filter type + */ + return apply_filters( 'ep_facet_meta_range_filter_type', 'meta-range' ); + } + + /** + * Add selected filters to the Facet filter in the ES query + * + * @param array $filters Current Facet filters + * @return array + */ + public function add_query_filters( $filters ) { + $feature = Features::factory()->get_registered_feature( 'facets' ); + + $all_selected_filters = $feature->get_selected(); + if ( empty( $all_selected_filters ) || empty( $all_selected_filters[ $this->get_filter_type() ] ) ) { + return $filters; + } + + $selected_range_filters = $all_selected_filters[ $this->get_filter_type() ]; + + $range_filters = []; + foreach ( $selected_range_filters as $field_name => $values ) { + foreach ( $values as $min_or_max => $value ) { + $operator = '_min' === $min_or_max ? 'gte' : 'lte'; + + $range_filters[ $field_name ][ $operator ] = floatval( $value ); + } + } + + foreach ( $range_filters as $field_name => $range_filter ) { + $filters[] = [ + 'range' => [ + 'meta.' . $field_name . '.double' => $range_filter, + ], + ]; + } + + return $filters; + } + + /** + * Add meta fields to facets aggs + * + * @param array $facet_aggs Facet Aggs array. + * @return array + */ + public function set_wp_query_aggs( $facet_aggs ) { + $facets_meta_fields = $this->get_facets_meta_fields(); + + foreach ( $facets_meta_fields as $meta_field ) { + /** + * Retrieve aggregations based on a custom field. This field must exist on the mapping and be numeric + * so ES can apply min and max to it. + * + * `meta..value` is *not* available, as that throws a `Fielddata is disabled on text fields by default` error. + * + * @since 4.5.0 + * @hook ep_facet_meta_range_use_field + * @param {string} $es_field The Elasticsearch field to use for this meta field + * @param {string} $meta_field The meta field key + * @return {string} The chosen ES field + */ + $facet_field = apply_filters( 'ep_facet_meta_range_use_field', 'double', $meta_field ); + + $facet_aggs[ $this->get_filter_name() . $meta_field . '_min' ] = array( + 'min' => array( + 'field' => 'meta.' . $meta_field . '.' . $facet_field, + ), + ); + + $facet_aggs[ $this->get_filter_name() . $meta_field . '_max' ] = array( + 'max' => array( + 'field' => 'meta.' . $meta_field . '.' . $facet_field, + ), + ); + } + + return $facet_aggs; + } + + /** + * Format selected values. + * + * For meta range facets, we will have `[ 'facet_name' => [ '_min' => X, '_max' => Y ] ]`; + * + * @since 4.5.0 + * @param string $facet Facet name + * @param mixed $value Facet value + * @param array $filters Selected filters + * @return array + */ + public function format_selected( string $facet, $value, array $filters ) { + $min_or_max = substr( $facet, -4 ); + $field_name = substr( $facet, 0, -4 ); + + $filters[ $this->get_filter_type() ][ $field_name ][ $min_or_max ] = $value; + + return $filters; + } + + /** + * Add selected filters to the query string. + * + * @since 4.5.0 + * @param array $query_params Existent query parameters + * @param array $filters Selected filters + * @return array + */ + public function add_query_params( array $query_params, array $filters ) : array { + $selected = $filters[ $this->get_filter_type() ]; + + foreach ( $selected as $facet => $values ) { + foreach ( $values as $min_or_max => $value ) { + $query_params[ $this->get_filter_name() . $facet . $min_or_max ] = $value; + } + } + + return $query_params; + } + + /** + * Get all fields selected in all Facet blocks + * + * @return array + */ + public function get_facets_meta_fields() { + $facets_meta_fields = []; + + $widget_block_instances = ( new \WP_Widget_Block() )->get_settings(); + foreach ( $widget_block_instances as $instance ) { + if ( ! isset( $instance['content'] ) ) { + continue; + } + + if ( false === strpos( $instance['content'], 'elasticpress/facet-meta-range' ) ) { + continue; + } + + if ( ! preg_match_all( '/"facet":"(.*?)"/', $instance['content'], $matches ) ) { + continue; + } + + $facets_meta_fields = array_merge( $facets_meta_fields, $matches[1] ); + } + + /** + * Filter meta fields to be used in aggregations related to meta range blocks. + * + * @since 4.5.0 + * @hook ep_facet_meta_range_fields + * @param {string} $facets_meta_fields Array of meta field keys + * @return {string} The array of meta field keys + */ + return apply_filters( 'ep_facet_meta_range_fields', $facets_meta_fields ); + } +} diff --git a/includes/classes/Feature/Facets/Types/MetaRange/Renderer.php b/includes/classes/Feature/Facets/Types/MetaRange/Renderer.php new file mode 100644 index 000000000..0fabd2c72 --- /dev/null +++ b/includes/classes/Feature/Facets/Types/MetaRange/Renderer.php @@ -0,0 +1,119 @@ +meta_field = $instance['facet']; + if ( empty( $this->meta_field ) ) { + if ( $instance['is_preview'] ) { + esc_html_e( 'Preview not available. Make sure you select a field.', 'elasticpress' ); + } + return false; + } + + if ( ! $this->should_render() ) { + return; + } + + $feature = Features::factory()->get_registered_feature( 'facets' ); + $facet_type = $feature->types['meta-range']; + + $min_field_name = $facet_type->get_filter_name() . $this->meta_field . '_min'; + $max_field_name = $facet_type->get_filter_name() . $this->meta_field . '_max'; + + if ( empty( $GLOBALS['ep_facet_aggs'][ $min_field_name ] ) + || empty( $GLOBALS['ep_facet_aggs'][ $max_field_name ] ) + ) { + if ( $instance['is_preview'] ) { + esc_html_e( 'Could not get min and max values. Is this a numeric field?', 'elasticpress' ); + } + return false; + } + + $min = $GLOBALS['ep_facet_aggs'][ $min_field_name ]; + $max = $GLOBALS['ep_facet_aggs'][ $max_field_name ]; + + $selected_min_value = null; + $selected_max_value = null; + + $selected_filters = $feature->get_selected(); + foreach ( $selected_filters[ $facet_type->get_filter_type() ] as $filter => $values ) { + if ( $this->meta_field !== $filter ) { + continue; + } + + $selected_min_value = $values['_min'] ?? null; + $selected_max_value = $values['_max'] ?? null; + unset( $selected_filters[ $facet_type->get_filter_type() ][ $filter ] ); + } + $form_action = wp_parse_url( $feature->build_query_url( $selected_filters ) ); + wp_parse_str( $form_action['query'] ?? '', $filter_fields ); + ?> +
+ $value ) { ?> + + + + + +
+

From to

+ get_registered_feature( 'facets' ); + if ( $wp_query->get( 'ep_facet', false ) && ! $feature->is_facetable( $wp_query ) ) { + return false; + } + + $es_success = ( ! empty( $wp_query->elasticsearch_success ) ) ? true : false; + if ( ! $es_success ) { + return false; + } + + return true; + } +} diff --git a/package-lock.json b/package-lock.json index 048785fcf..5ef4c7fd0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ }, "devDependencies": { "@4tw/cypress-drag-drop": "^2.2.1", + "@cypress/grep": "^3.1.3", "@wordpress/env": "^5.0.0", "10up-toolkit": "^4.3.1", "classnames": "^2.3.1", @@ -2295,6 +2296,20 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@cypress/grep": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@cypress/grep/-/grep-3.1.3.tgz", + "integrity": "sha512-kuifujYlCBKzOtkiFwa8mg18SusXoQOELMgJu8l4ffqpgZg2fukwLGaO1K7qgL8V9ZSu6OhJh8CJRbI99A+snQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "find-test-names": "^1.19.0", + "globby": "^11.0.4" + }, + "peerDependencies": { + "cypress": ">=10" + } + }, "node_modules/@cypress/request": { "version": "2.88.10", "dev": true, @@ -5159,6 +5174,15 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.1", "dev": true, @@ -5895,6 +5919,104 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "dev": true, @@ -6357,6 +6479,18 @@ "node": ">=6" } }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "dev": true, @@ -6657,6 +6791,23 @@ "typedarray": "^0.0.6" } }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/confusing-browser-globals": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", @@ -6944,6 +7095,15 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/css-blank-pseudo": { "version": "3.0.3", "dev": true, @@ -7927,12 +8087,30 @@ "tslib": "^2.0.3" } }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "dev": true + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "dev": true, @@ -8140,6 +8318,15 @@ "node": ">=6" } }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -9470,6 +9657,33 @@ "integrity": "sha512-o4UcykWV/XN9wm+jMEtWLPlV8RXCZnMhQI6F6OdHeSez7iiJWePw8ijOlskJZMsaQoGR/b7dH6lO02HhaTN7+A==", "dev": true }, + "node_modules/find-test-names": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/find-test-names/-/find-test-names-1.22.2.tgz", + "integrity": "sha512-+DZOP+kRoMOelHt9lYCuIP6WDxbIDauNdwaQdsVhZ24XZz0OHvnS8ThIcAxczCeeU4pgDRYtZIztPvML7VoFzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.16.5", + "acorn-walk": "^8.2.0", + "debug": "^4.3.3", + "globby": "^11.0.4", + "simple-bin-help": "^1.7.7" + }, + "bin": { + "find-test-names": "bin/find-test-names.js", + "print-tests": "bin/print-tests.js", + "update-test-count": "bin/update-test-count.js" + } + }, + "node_modules/find-test-names/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -10047,6 +10261,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -10897,6 +11120,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -10921,6 +11156,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "dev": true, @@ -11062,6 +11306,12 @@ "node": ">=8" } }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, "node_modules/isarray": { "version": "1.0.0", "dev": true, @@ -13205,6 +13455,18 @@ "language-subtag-registry": "^0.3.20" } }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lazy-ass": { "version": "1.6.0", "dev": true, @@ -14658,6 +14920,172 @@ "node": ">=6" } }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json/node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json/node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/package-json/node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "node_modules/package-json/node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/package-json/node_modules/got/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json/node_modules/got/node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/package-json/node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "dev": true + }, + "node_modules/package-json/node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/package-json/node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json/node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "dev": true, + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/package-json/node_modules/responselike/node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -16160,6 +16588,15 @@ "node": ">= 0.8.0" } }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/prettier": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", @@ -16324,6 +16761,18 @@ "node": ">=6" } }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/qs": { "version": "6.5.3", "dev": true, @@ -16766,6 +17215,30 @@ "node": ">=4" } }, + "node_modules/registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "dev": true, + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/regjsgen": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", @@ -17178,6 +17651,18 @@ "semver": "bin/semver.js" } }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -17426,6 +17911,26 @@ "dev": true, "license": "ISC" }, + "node_modules/simple-bin-help": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/simple-bin-help/-/simple-bin-help-1.7.7.tgz", + "integrity": "sha512-e36uqSXbTL0yNUc7RgjMFAEMDgV5jbPd18LrCeswZJ7aUtEq0qPf4rroQyW3Tfl1E7rcsW1amZoV3OCGOne1Tg==", + "dev": true, + "dependencies": { + "debug": "3.2.7", + "update-notifier": "5.1.0", + "word-wrap": "1.2.3" + } + }, + "node_modules/simple-bin-help/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -18658,6 +19163,15 @@ "node": ">=4" } }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -18936,6 +19450,18 @@ "node": ">=4" } }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/universalify": { "version": "2.0.0", "dev": true, @@ -18987,6 +19513,140 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/update-notifier/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/update-notifier/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/update-notifier/node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/update-notifier/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/update-notifier/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/upper-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", @@ -19048,6 +19708,18 @@ "requires-port": "^1.0.0" } }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "dev": true, + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/use-memo-one": { "version": "1.1.2", "license": "MIT", @@ -19738,6 +20410,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "dev": true, @@ -19830,6 +20514,15 @@ } } }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", @@ -21429,6 +22122,17 @@ "dev": true, "requires": {} }, + "@cypress/grep": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@cypress/grep/-/grep-3.1.3.tgz", + "integrity": "sha512-kuifujYlCBKzOtkiFwa8mg18SusXoQOELMgJu8l4ffqpgZg2fukwLGaO1K7qgL8V9ZSu6OhJh8CJRbI99A+snQ==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "find-test-names": "^1.19.0", + "globby": "^11.0.4" + } + }, "@cypress/request": { "version": "2.88.10", "dev": true, @@ -23513,6 +24217,15 @@ "dev": true, "requires": {} }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, "ansi-colors": { "version": "4.1.1", "dev": true @@ -24035,6 +24748,73 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, "brace-expansion": { "version": "1.1.11", "dev": true, @@ -24366,6 +25146,12 @@ "version": "2.2.0", "dev": true }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, "cli-cursor": { "version": "3.1.0", "dev": true, @@ -24589,6 +25375,20 @@ "typedarray": "^0.0.6" } }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, "confusing-browser-globals": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", @@ -24788,6 +25588,12 @@ "which": "^2.0.1" } }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, "css-blank-pseudo": { "version": "3.0.3", "dev": true, @@ -25480,12 +26286,27 @@ "tslib": "^2.0.3" } }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, "duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, + "duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "dev": true + }, "ecc-jsbn": { "version": "0.1.2", "dev": true, @@ -25646,6 +26467,12 @@ "version": "3.1.1", "dev": true }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -26595,6 +27422,27 @@ "integrity": "sha512-o4UcykWV/XN9wm+jMEtWLPlV8RXCZnMhQI6F6OdHeSez7iiJWePw8ijOlskJZMsaQoGR/b7dH6lO02HhaTN7+A==", "dev": true }, + "find-test-names": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/find-test-names/-/find-test-names-1.22.2.tgz", + "integrity": "sha512-+DZOP+kRoMOelHt9lYCuIP6WDxbIDauNdwaQdsVhZ24XZz0OHvnS8ThIcAxczCeeU4pgDRYtZIztPvML7VoFzA==", + "dev": true, + "requires": { + "@babel/parser": "^7.16.5", + "acorn-walk": "^8.2.0", + "debug": "^4.3.3", + "globby": "^11.0.4", + "simple-bin-help": "^1.7.7" + }, + "dependencies": { + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + } + } + }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -26991,6 +27839,12 @@ "has-symbols": "^1.0.2" } }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -27559,6 +28413,12 @@ "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true }, + "is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -27574,6 +28434,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, "is-path-inside": { "version": "3.0.3", "dev": true @@ -27663,6 +28529,12 @@ "is-docker": "^2.0.0" } }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, "isarray": { "version": "1.0.0", "dev": true @@ -29242,6 +30114,15 @@ "language-subtag-registry": "^0.3.20" } }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, "lazy-ass": { "version": "1.6.0", "dev": true @@ -30254,6 +31135,145 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + } + } + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "dev": true + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + } + } + } + } + }, "param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -31163,6 +32183,12 @@ "dev": true, "peer": true }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "dev": true + }, "prettier": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", @@ -31283,6 +32309,15 @@ "version": "2.1.1", "dev": true }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, "qs": { "version": "6.5.3", "dev": true @@ -31606,6 +32641,24 @@ "unicode-match-property-value-ecmascript": "^2.1.0" } }, + "registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "dev": true, + "requires": { + "rc": "1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, "regjsgen": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", @@ -31884,6 +32937,15 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + } + }, "send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -32096,6 +33158,28 @@ "version": "3.0.7", "dev": true }, + "simple-bin-help": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/simple-bin-help/-/simple-bin-help-1.7.7.tgz", + "integrity": "sha512-e36uqSXbTL0yNUc7RgjMFAEMDgV5jbPd18LrCeswZJ7aUtEq0qPf4rroQyW3Tfl1E7rcsW1amZoV3OCGOne1Tg==", + "dev": true, + "requires": { + "debug": "3.2.7", + "update-notifier": "5.1.0", + "word-wrap": "1.2.3" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, "simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -33016,6 +34100,12 @@ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -33220,6 +34310,15 @@ "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, "universalify": { "version": "2.0.0", "dev": true @@ -33244,6 +34343,103 @@ "picocolors": "^1.0.0" } }, + "update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "requires": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "upper-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", @@ -33288,6 +34484,15 @@ "requires-port": "^1.0.0" } }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, "use-memo-one": { "version": "1.1.2", "requires": {} @@ -33786,6 +34991,15 @@ "is-symbol": "^1.0.3" } }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, "word-wrap": { "version": "1.2.3", "dev": true @@ -33842,6 +35056,12 @@ "dev": true, "requires": {} }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", diff --git a/package.json b/package.json index 4e0008851..dbbb93747 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "description": "A fast and flexible search and query engine for WordPress.", "devDependencies": { "@4tw/cypress-drag-drop": "^2.2.1", + "@cypress/grep": "^3.1.3", "@wordpress/env": "^5.0.0", "10up-toolkit": "^4.3.1", "classnames": "^2.3.1", @@ -59,6 +60,7 @@ "ordering-script": "./assets/js/ordering/index.js", "facets-block-script": "./assets/js/blocks/facets/taxonomy/index.js", "facets-meta-block-script": "./assets/js/blocks/facets/meta/index.js", + "facets-meta-range-block-script": "./assets/js/blocks/facets/meta-range/index.js", "related-posts-block-script": "./assets/js/blocks/related-posts/index.js", "settings-script": "./assets/js/settings.js", "sync-script": "./assets/js/sync/index.js", diff --git a/tests/cypress/README.md b/tests/cypress/README.md index 3b28a7092..88e16d383 100644 --- a/tests/cypress/README.md +++ b/tests/cypress/README.md @@ -21,7 +21,7 @@ ElasticPress e2e tests use [Cypress](https://www.cypress.io/), [wp-env](https:// ### Reset * Destroy the WP env: `npm run env destroy` -* Restart WP env and redo initial setup: `npm run env start && npm run cypress:setup` +* Restart WP env and redo initial setup: `npm run env:start && npm run cypress:setup` * Open Cypress: `npm run cypress:open` ## Troubleshooting diff --git a/tests/cypress/config.js b/tests/cypress/config.js index 1b34308ec..51bc5a117 100644 --- a/tests/cypress/config.js +++ b/tests/cypress/config.js @@ -13,6 +13,7 @@ module.exports = defineConfig({ e2e: { async setupNodeEvents(on, config) { /* eslint-disable global-require */ + require('@cypress/grep/src/plugin')(config); const path = require('path'); const { readConfig } = require('@wordpress/env/lib/config'); /* eslint-enable global-require */ @@ -32,6 +33,10 @@ module.exports = defineConfig({ return config; }, + env: { + grepFilterSpecs: true, + grepOmitFiltered: true, + }, specPattern: 'tests/cypress/integration/**/*.cy.{js,jsx,ts,tsx}', supportFile: 'tests/cypress/support/index.js', }, diff --git a/tests/cypress/integration/features/comments.cy.js b/tests/cypress/integration/features/comments.cy.js index e78f64371..88eb6be23 100644 --- a/tests/cypress/integration/features/comments.cy.js +++ b/tests/cypress/integration/features/comments.cy.js @@ -1,4 +1,5 @@ -describe('Comments Feature', () => { +// eslint-disable-next-line jest/valid-describe-callback +describe('Comments Feature', { tags: '@slow' }, () => { const defaultApprovedComments = 26; /** diff --git a/tests/cypress/integration/features/facets.cy.js b/tests/cypress/integration/features/facets.cy.js index 4d9659aa4..3f9939720 100644 --- a/tests/cypress/integration/features/facets.cy.js +++ b/tests/cypress/integration/features/facets.cy.js @@ -1,4 +1,5 @@ -describe('Facets Feature', () => { +// eslint-disable-next-line jest/valid-describe-callback +describe('Facets Feature', { tags: '@slow' }, () => { /** * Ensure the feature is active, perform a sync, and remove test posts * before running tests. diff --git a/tests/cypress/integration/features/instant-results.cy.js b/tests/cypress/integration/features/instant-results.cy.js index 70e81dc56..4ae666cd5 100644 --- a/tests/cypress/integration/features/instant-results.cy.js +++ b/tests/cypress/integration/features/instant-results.cy.js @@ -1,6 +1,7 @@ /* global isEpIo */ -describe('Instant Results Feature', () => { +// eslint-disable-next-line jest/valid-describe-callback +describe('Instant Results Feature', { tags: '@slow' }, () => { /** * Create a Search widget. * @@ -17,6 +18,7 @@ describe('Instant Results Feature', () => { } before(() => { + cy.deactivatePlugin('classic-widgets', 'wpCli'); createSearchWidget(); // Create some sample posts @@ -95,126 +97,132 @@ describe('Instant Results Feature', () => { .should('contain', 'instant-results'); }); - /** - * Test that the instant results list is visible - * It can display the number of test results - * It can show the modal in the same state after a reload - * Can change the URL when search term is changed - */ - it('Can see instant results elements, URL changes, reload, and update after changing search term', () => { - cy.maybeEnableFeature('instant-results'); - - cy.intercept('*search=blog*').as('apiRequest'); - - cy.visit('/'); - - cy.get('.wp-block-search').last().as('searchBlock'); - - cy.get('@searchBlock').find('.wp-block-search__input').type('blog'); - cy.get('@searchBlock').find('.wp-block-search__button').click(); - cy.get('.ep-search-modal').as('searchModal').should('be.visible'); // Should be visible immediatly - cy.url().should('include', 'search=blog'); - - cy.wait('@apiRequest'); - cy.get('@searchModal').should('contain.text', 'blog'); - // Show the number of results - cy.get('@searchModal').find('.ep-search-results__title').contains(/\d+/); - - cy.get('.ep-search-sidebar #ep-search-post-type-post') - .click() - .then(() => { - cy.url().should('include', 'ep-post_type=post'); - }); - - // Show the modal in the same state after a reload - cy.reload(); - cy.wait('@apiRequest'); - cy.get('@searchModal').should('be.visible').should('contain.text', 'blog'); - - // Update the results when search term is changed - cy.get('@searchModal') - .find('.ep-search-input') - .clearThenType('test') - .then(() => { - cy.wait('@apiRequest'); - cy.get('@searchModal').should('be.visible').should('contain.text', 'test'); - cy.url().should('include', 'search=test'); - }); - - cy.get('#wpadminbar li#wp-admin-bar-debug-bar').click(); - cy.get('#querylist').should('be.visible'); - }); - - it('Is possible to manually open Instant Results with a plugin', () => { - Cypress.on( - 'uncaught:exception', - (err) => !err.message.includes('ResizeObserver loop limit exceeded'), - ); - - /** - * Activate test plugin with JavaScript. - */ - cy.maybeEnableFeature('instant-results'); - cy.activatePlugin('open-instant-results-with-buttons', 'wpCli'); - - /** - * Create a post with a Buttons block. - */ - cy.publishPost({ - title: `Test openModal()`, - content: 'Testing openModal()', + describe('Instant Results activated', () => { + before(() => { + cy.wpCli('wp elasticpress put-search-template', true); }); - cy.openBlockInserter(); - cy.insertBlock('Buttons'); - cy.get('.wp-block-button__link').type('Search "Block"'); - - /** - * Update the post and visit the front end. - */ - cy.get('.editor-post-publish-button__button').click(); - cy.get('.components-snackbar__action').click(); - /** - * Click the button. + * Test that the instant results list is visible + * It can display the number of test results + * It can show the modal in the same state after a reload + * Can change the URL when search term is changed */ - cy.intercept('*search=block*').as('apiRequest'); - cy.get('.wp-block-button__link').click(); - - /** - * Instant Results should be open and populated with our search term. - */ - cy.wait('@apiRequest'); - cy.get('.ep-search-modal').as('searchModal').should('be.visible'); - cy.get('@searchModal').find('.ep-search-input').should('have.value', 'block'); - cy.get('@searchModal') - .find('.ep-search-results__title') - .should('contain.text', 'block'); - }); + it('Can see instant results elements, URL changes, reload, and update after changing search term', () => { + cy.maybeEnableFeature('instant-results'); + + cy.intercept('*search=blog*').as('apiRequest'); + + cy.visit('/'); + + cy.get('.wp-block-search').last().as('searchBlock'); + + cy.get('@searchBlock').find('.wp-block-search__input').type('blog'); + cy.get('@searchBlock').find('.wp-block-search__button').click(); + cy.get('.ep-search-modal').as('searchModal').should('be.visible'); // Should be visible immediatly + cy.url().should('include', 'search=blog'); + + cy.wait('@apiRequest'); + cy.get('@searchModal').should('contain.text', 'blog'); + // Show the number of results + cy.get('@searchModal').find('.ep-search-results__title').contains(/\d+/); + + cy.get('.ep-search-sidebar #ep-search-post-type-post') + .click() + .then(() => { + cy.url().should('include', 'ep-post_type=post'); + }); + + // Show the modal in the same state after a reload + cy.reload(); + cy.wait('@apiRequest'); + cy.get('@searchModal').should('be.visible').should('contain.text', 'blog'); + + // Update the results when search term is changed + cy.get('@searchModal') + .find('.ep-search-input') + .clearThenType('test') + .then(() => { + cy.wait('@apiRequest'); + cy.get('@searchModal').should('be.visible').should('contain.text', 'test'); + cy.url().should('include', 'search=test'); + }); + + cy.get('#wpadminbar li#wp-admin-bar-debug-bar').click(); + cy.get('#querylist').should('be.visible'); + }); - it('Can filter the result template', () => { - /** - * Activate test plugin with filter. - */ - cy.maybeEnableFeature('instant-results'); - cy.activatePlugin('custom-instant-results-template', 'wpCli'); + it('Is possible to manually open Instant Results with a plugin', () => { + Cypress.on( + 'uncaught:exception', + (err) => !err.message.includes('ResizeObserver loop limit exceeded'), + ); + + /** + * Activate test plugin with JavaScript. + */ + cy.maybeEnableFeature('instant-results'); + cy.activatePlugin('open-instant-results-with-buttons', 'wpCli'); + + /** + * Create a post with a Buttons block. + */ + cy.publishPost({ + title: `Test openModal()`, + content: 'Testing openModal()', + }); - /** - * Perform a search. - */ - cy.intercept('*search=blog*').as('apiRequest'); - cy.visit('/'); - cy.get('.wp-block-search').last().as('searchBlock'); - cy.get('@searchBlock').find('input[type="search"]').type('blog'); - cy.get('@searchBlock').find('button').click(); - cy.get('.ep-search-modal').should('be.visible'); - cy.wait('@apiRequest'); + cy.openBlockInserter(); + cy.insertBlock('Buttons'); + cy.get('.wp-block-button__link').type('Search "Block"'); + + /** + * Update the post and visit the front end. + */ + cy.get('.editor-post-publish-button__button').click(); + cy.get('.components-snackbar__action').click(); + + /** + * Click the button. + */ + cy.intercept('*search=block*').as('apiRequest'); + cy.get('.wp-block-button__link').click(); + + /** + * Instant Results should be open and populated with our search term. + */ + cy.wait('@apiRequest'); + cy.get('.ep-search-modal').as('searchModal').should('be.visible'); + cy.get('@searchModal').find('.ep-search-input').should('have.value', 'block'); + cy.get('@searchModal') + .find('.ep-search-results__title') + .should('contain.text', 'block'); + }); - /** - * Results should use the filtered template with a custom class. - */ - cy.get('.my-custom-result').should('exist'); - cy.get('.ep-search-result').should('not.exist'); + it('Can filter the result template', () => { + /** + * Activate test plugin with filter. + */ + cy.maybeEnableFeature('instant-results'); + cy.activatePlugin('custom-instant-results-template', 'wpCli'); + + /** + * Perform a search. + */ + cy.intercept('*search=blog*').as('apiRequest'); + cy.visit('/'); + cy.get('.wp-block-search').last().as('searchBlock'); + cy.get('@searchBlock').find('input[type="search"]').type('blog'); + cy.get('@searchBlock').find('button').click(); + cy.get('.ep-search-modal').should('be.visible'); + cy.wait('@apiRequest'); + + /** + * Results should use the filtered template with a custom class. + */ + cy.get('.my-custom-result').should('exist'); + cy.get('.ep-search-result').should('not.exist'); + }); }); }); }); diff --git a/tests/cypress/integration/features/search/search.cy.js b/tests/cypress/integration/features/search/search.cy.js index 5bf50d048..ba8823071 100644 --- a/tests/cypress/integration/features/search/search.cy.js +++ b/tests/cypress/integration/features/search/search.cy.js @@ -1,4 +1,5 @@ -describe('Post Search Feature', () => { +// eslint-disable-next-line jest/valid-describe-callback +describe('Post Search Feature', { tags: '@slow' }, () => { before(() => { cy.wpCli('elasticpress sync --setup --yes'); }); diff --git a/tests/cypress/integration/features/terms.cy.js b/tests/cypress/integration/features/terms.cy.js index b2fa73d40..c70597934 100644 --- a/tests/cypress/integration/features/terms.cy.js +++ b/tests/cypress/integration/features/terms.cy.js @@ -1,4 +1,5 @@ -describe('Terms Feature', () => { +// eslint-disable-next-line jest/valid-describe-callback +describe('Terms Feature', { tags: '@slow' }, () => { const tags = ['Far From Home', 'No Way Home', 'The Most Fun Thing']; before(() => { diff --git a/tests/cypress/integration/features/woocommerce.cy.js b/tests/cypress/integration/features/woocommerce.cy.js index f6b942d8e..984f2aef4 100644 --- a/tests/cypress/integration/features/woocommerce.cy.js +++ b/tests/cypress/integration/features/woocommerce.cy.js @@ -1,4 +1,5 @@ -describe('WooCommerce Feature', () => { +// eslint-disable-next-line jest/valid-describe-callback +describe('WooCommerce Feature', { tags: '@slow' }, () => { const userData = { username: 'testuser', email: 'testuser@example.com', diff --git a/tests/cypress/integration/general.cy.js b/tests/cypress/integration/general.cy.js index 6b6b3f7bd..9e9a50184 100644 --- a/tests/cypress/integration/general.cy.js +++ b/tests/cypress/integration/general.cy.js @@ -1,4 +1,5 @@ -describe('WordPress can perform standard ElasticPress actions', () => { +// eslint-disable-next-line jest/valid-describe-callback +describe('WordPress can perform standard ElasticPress actions', { tags: '@slow' }, () => { it('Can see the settings page link in WordPress Dashboard', () => { cy.login(); diff --git a/tests/cypress/integration/indexables/post.cy.js b/tests/cypress/integration/indexables/post.cy.js index c9719171f..b30719ca7 100644 --- a/tests/cypress/integration/indexables/post.cy.js +++ b/tests/cypress/integration/indexables/post.cy.js @@ -6,6 +6,12 @@ describe('Post Indexable', () => { * - the `Block` (ID 54) term has 7 posts * Important: There is no post with both categories, as that would skew results. */ + + // Make sure post categories are searchable. + cy.visitAdminPage('admin.php?page=elasticpress-weighting'); + cy.get('#post-terms\\.category\\.name-enabled').check(); + cy.get('#submit').click(); + cy.setPerIndexCycle(); cy.visitAdminPage('edit-tags.php?taxonomy=category'); cy.get('div[data-ep-notice="too_many_posts_on_term"]').should('not.exist'); diff --git a/tests/cypress/integration/wp-cli.cy.js b/tests/cypress/integration/wp-cli.cy.js index 7d8dad94c..a22173247 100644 --- a/tests/cypress/integration/wp-cli.cy.js +++ b/tests/cypress/integration/wp-cli.cy.js @@ -1,6 +1,7 @@ /* global indexNames */ -describe('WP-CLI Commands', () => { +// eslint-disable-next-line jest/valid-describe-callback +describe('WP-CLI Commands', { tags: '@slow' }, () => { let indexAllSitesNames = []; function checkIfNotMissingIndexes(mode = 'singleSite') { diff --git a/tests/cypress/support/index.js b/tests/cypress/support/index.js index 8d9ac3051..ca4be5d12 100644 --- a/tests/cypress/support/index.js +++ b/tests/cypress/support/index.js @@ -18,6 +18,11 @@ import './assertions'; import './commands'; import './global-hooks'; +// Import cypress grep +import registerCypressGrep from '@cypress/grep'; + +registerCypressGrep(); + // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/tests/php/features/TestFacetTypeMetaRange.php b/tests/php/features/TestFacetTypeMetaRange.php new file mode 100644 index 000000000..d4d13cc15 --- /dev/null +++ b/tests/php/features/TestFacetTypeMetaRange.php @@ -0,0 +1,228 @@ +get_registered_feature( 'facets' ); + if ( ! isset( $facet_feature->types['meta-range'] ) && class_exists( '\ElasticPress\Feature\Facets\Types\MetaRange\FacetType' ) ) { + $facet_feature->types['meta-range'] = new \ElasticPress\Feature\Facets\Types\MetaRange\FacetType(); + $facet_feature->types['meta-range']->setup(); + } + + $facet_feature = Features::factory()->get_registered_feature( 'facets' ); + $this->facet_type = $facet_feature->types['meta-range']; + + parent::set_up(); + } + + /** + * Test get_filter_name + * + * @group facets + */ + public function testGetFilterName() { + /** + * Test default behavior + */ + $this->assertEquals( 'ep_meta_range_filter_', $this->facet_type->get_filter_name() ); + + /** + * Test the `ep_facet_meta_filter_name` filter + */ + $change_filter_name = function( $filter_name ) { + return $filter_name . '_'; + }; + add_filter( 'ep_facet_meta_range_filter_name', $change_filter_name ); + $this->assertEquals( 'ep_meta_range_filter__', $this->facet_type->get_filter_name() ); + } + + /** + * Test get_filter_type + * + * @group facets + */ + public function testGetFilterType() { + /** + * Test default behavior + */ + $this->assertEquals( 'meta-range', $this->facet_type->get_filter_type() ); + + /** + * Test the `ep_facet_filter_type` filter + */ + $change_filter_type = function( $filter_type ) { + return $filter_type . '_'; + }; + add_filter( 'ep_facet_meta_range_filter_type', $change_filter_type ); + $this->assertEquals( 'meta-range_', $this->facet_type->get_filter_type() ); + } + + /** + * Test add_query_filters + * + * @group facets + */ + public function testAddQueryFilters() { + parse_str( 'ep_meta_range_filter_my_custom_field_min=5&ep_meta_range_filter_my_custom_field_max=25', $_GET ); + + $new_filters = $this->facet_type->add_query_filters( [] ); + $expected = [ + [ + 'range' => [ + 'meta.my_custom_field.double' => [ + 'gte' => floatval( 5 ), + 'lte' => floatval( 25 ), + ], + ], + ], + ]; + $this->assertSame( $expected, $new_filters ); + } + + /** + * Test set_wp_query_aggs + * + * @group facets + */ + public function testSetWpQueryAggs() { + $set_facet_meta_field = function() { + return [ 'new_meta_key_1', 'new_meta_key_2' ]; + }; + add_filter( 'ep_facet_meta_range_fields', $set_facet_meta_field ); + + $with_aggs = $this->facet_type->set_wp_query_aggs( [] ); + + /** + * Test default behavior + */ + $default_min_agg = [ + 'min' => [ + 'field' => 'meta.new_meta_key_1.double', + ], + ]; + $this->assertSame( $with_aggs['ep_meta_range_filter_new_meta_key_1_min'], $default_min_agg ); + $default_max_agg = [ + 'max' => [ + 'field' => 'meta.new_meta_key_1.double', + ], + ]; + $this->assertSame( $with_aggs['ep_meta_range_filter_new_meta_key_1_max'], $default_max_agg ); + + /** + * Test the `ep_facet_meta_use_field` filter + */ + $change_meta_facet_field = function( $es_field, $meta_field ) { + return ( 'new_meta_key_1' === $meta_field ) ? 'long' : $es_field; + }; + + add_filter( 'ep_facet_meta_use_field', $change_meta_facet_field, 10, 2 ); + + $with_aggs = $this->facet_type->set_wp_query_aggs( [] ); + $this->assertSame( 'meta.new_meta_key_1.double', $with_aggs['ep_meta_range_filter_new_meta_key_1_min']['min']['field'] ); + $this->assertSame( 'meta.new_meta_key_1.double', $with_aggs['ep_meta_range_filter_new_meta_key_1_max']['max']['field'] ); + $this->assertSame( 'meta.new_meta_key_2.double', $with_aggs['ep_meta_range_filter_new_meta_key_2_min']['min']['field'] ); + $this->assertSame( 'meta.new_meta_key_2.double', $with_aggs['ep_meta_range_filter_new_meta_key_2_max']['max']['field'] ); + + remove_filter( 'ep_facet_meta_use_field', $change_meta_facet_field ); + } + + /** + * Test the format_selected method. + */ + public function testFormatSelected() { + $original_filters = [ 'custom_type' => [ 'facet' => [ 1, 2, 3 ] ] ]; + $new_filters = $this->facet_type->format_selected( 'my_meta_min', '5', $original_filters ); + $expected_filters = array_merge( + $original_filters, + [ + $this->facet_type->get_filter_type() => [ + 'my_meta' => [ + '_min' => '5', + ], + ], + ] + ); + + $this->assertSame( $new_filters, $expected_filters ); + + /** + * Analyzing tags=slug3,slug4 should ADD tags, keeping the category index. + */ + $original_filters = $expected_filters; + $new_filters = $this->facet_type->format_selected( 'my_meta_max', '25', $original_filters ); + + $expected_filters[ $this->facet_type->get_filter_type() ]['my_meta'] = [ + '_min' => '5', + '_max' => '25', + ]; + + $this->assertSame( $new_filters, $expected_filters ); + } + + /** + * Test the add_query_params method. + */ + public function testAddQueryParams() { + $original_query_params = [ 'custom_name' => 'custom_value' ]; + $selected_filters = [ + [ + 'custom_type' => [ 'facet' => [ 1, 2, 3 ] ] + ], + $this->facet_type->get_filter_type() => [ + 'my_meta_1' => [ + '_min' => '5', + '_max' => '25', + ], + 'my_meta_2' => [ + '_min' => '10', + '_max' => '50', + ], + ], + ]; + + $new_query_params = $this->facet_type->add_query_params( $original_query_params, $selected_filters ); + $expected_query_params = array_merge( + $original_query_params, + [ + $this->facet_type->get_filter_name() . 'my_meta_1_min' => '5', + $this->facet_type->get_filter_name() . 'my_meta_1_max' => '25', + $this->facet_type->get_filter_name() . 'my_meta_2_min' => '10', + $this->facet_type->get_filter_name() . 'my_meta_2_max' => '50', + ] + ); + + $this->assertSame( $new_query_params, $expected_query_params ); + } + + /** + * Test get_facets_meta_fields + * + * @group facets + */ + public function testGetFacetsMetaFields() { + $this->markTestIncomplete(); + } +} diff --git a/tests/php/features/TestFacetTypeTaxonomy.php b/tests/php/features/TestFacetTypeTaxonomy.php index 1457de457..5947264b7 100644 --- a/tests/php/features/TestFacetTypeTaxonomy.php +++ b/tests/php/features/TestFacetTypeTaxonomy.php @@ -201,7 +201,6 @@ public function testAddQueryFilters() { * @group facets */ public function testGetSanitizeCallback() { - $facet_feature = Features::factory()->get_registered_feature( 'facets' ); $test_taxonomy = 'This is a test taxonomy'; @@ -228,4 +227,91 @@ public function testGetSanitizeCallback() { $expected_result = sanitize_text_field( $test_taxonomy ); $this->assertArrayHasKey( $expected_result, $selected['taxonomies']['taxonomy']['terms'] ); } + + /** + * Test the format_selected method. + * + * @todo Move this to a mock, as it is just inherited now + * @since 4.5.0 + */ + public function testFormatSelected() { + $facet_feature = Features::factory()->get_registered_feature( 'facets' ); + $facet_type = $facet_feature->types['taxonomy']; + + $original_filters = [ 'custom_type' => [ 'facet' => [ 1, 2, 3 ] ] ]; + $new_filters = $facet_type->format_selected( 'category', 'slug1,slug2', $original_filters ); + $expected_filters = array_merge( + $original_filters, + [ + $facet_type->get_filter_type() => [ + 'category' => [ + 'terms' => [ + 'slug1' => true, + 'slug2' => true, + ], + ], + ], + ] + ); + + $this->assertSame( $new_filters, $expected_filters ); + + /** + * Analyzing tags=slug3,slug4 should ADD tags, keeping the category index. + */ + $original_filters = $expected_filters; + $new_filters = $facet_type->format_selected( 'tags', 'slug3,slug4', $original_filters ); + + $expected_filters[ $facet_type->get_filter_type() ]['tags'] = [ + 'terms' => [ + 'slug3' => true, + 'slug4' => true, + ], + ]; + + $this->assertSame( $new_filters, $expected_filters ); + } + + /** + * Test the add_query_params method. + * + * @todo Move this to a mock, as it is just inherited now + * @since 4.5.0 + */ + public function testAddQueryParams() { + $facet_feature = Features::factory()->get_registered_feature( 'facets' ); + $facet_type = $facet_feature->types['taxonomy']; + + $original_query_params = [ 'custom_name' => 'custom_value' ]; + $selected_filters = [ + [ + 'custom_type' => [ 'facet' => [ 1, 2, 3 ] ] + ], + $facet_type->get_filter_type() => [ + 'category' => [ + 'terms' => [ + 'slug1' => true, + 'slug2' => true, + ], + ], + 'tags' => [ + 'terms' => [ + 'slug3' => true, + 'slug4' => true, + ], + ], + ], + ]; + + $new_query_params = $facet_type->add_query_params( $original_query_params, $selected_filters ); + $expected_query_params = array_merge( + $original_query_params, + [ + $facet_type->get_filter_name() . 'category' => 'slug1,slug2', + $facet_type->get_filter_name() . 'tags' => 'slug3,slug4', + ] + ); + + $this->assertSame( $new_query_params, $expected_query_params ); + } }