From adfabb699d6ace0fcc2df1f703aa270ae9bae0be Mon Sep 17 00:00:00 2001 From: Dharmesh Patel Date: Wed, 20 Mar 2024 20:28:04 +0530 Subject: [PATCH] Add E2E tests. --- .../Classifai/Providers/AWS/AmazonPolly.php | 40 +++++- .../text-to-speech-amazon-polly.test.js | 116 ++++++++++++++++++ tests/test-plugin/amazon-polly-voices.json | 28 +++++ tests/test-plugin/e2e-test-plugin.php | 15 +++ 4 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 tests/cypress/integration/language-processing/text-to-speech-amazon-polly.test.js create mode 100644 tests/test-plugin/amazon-polly-voices.json diff --git a/includes/Classifai/Providers/AWS/AmazonPolly.php b/includes/Classifai/Providers/AWS/AmazonPolly.php index a9ddc3a8e..044c0bd81 100644 --- a/includes/Classifai/Providers/AWS/AmazonPolly.php +++ b/includes/Classifai/Providers/AWS/AmazonPolly.php @@ -278,6 +278,23 @@ public function connect_to_service( array $args = array() ): array { } try { + /** + * Filters the return value of the connect to services function. + * + * Returning a non-false value from the filter will short-circuit the describe voices request and return early with that value. + * This filter is useful for E2E tests. + * + * @since 3.1.0 + * + * @param false|mixed $response A return value of connect to service. Default false. + * @param array $synthesize_data HTTP request arguments. + */ + $pre = apply_filters( 'classifai_' . self::ID . '_pre_connect_to_service', false ); + + if ( false !== $pre ) { + return $pre; + } + $polly_client = $this->get_polly_client( $args ); $polly_voices = $polly_client->describeVoices(); return $polly_voices->get( 'Voices' ); @@ -377,8 +394,6 @@ public function synthesize_speech( int $post_id ) { $voice = $settings[ static::ID ]['voice'] ?? ''; try { - $polly_client = $this->get_polly_client(); - /** * Filter Synthesize speech args. * @@ -406,7 +421,26 @@ public function synthesize_speech( int $post_id ) { $this->feature_instance ); - $result = $polly_client->synthesizeSpeech( $synthesize_data ); + + /** + * Filters the return value of the synthesize speech function. + * + * Returning a non-false value from the filter will short-circuit the synthesize speech request and return early with that value. + * This filter is useful for E2E tests. + * + * @since 3.1.0 + * + * @param false|mixed $response A return value of synthesize speech. Default false. + * @param array $synthesize_data HTTP request arguments. + */ + $pre = apply_filters( 'classifai_' . self::ID . '_pre_synthesize_speech', false, $synthesize_data ); + + if ( false !== $pre ) { + return $pre; + } + + $polly_client = $this->get_polly_client(); + $result = $polly_client->synthesizeSpeech( $synthesize_data ); update_post_meta( $post_id, self::AUDIO_HASH_KEY, md5( $post_content ) ); $contents = $result['AudioStream']->getContents(); diff --git a/tests/cypress/integration/language-processing/text-to-speech-amazon-polly.test.js b/tests/cypress/integration/language-processing/text-to-speech-amazon-polly.test.js new file mode 100644 index 000000000..27ffccf47 --- /dev/null +++ b/tests/cypress/integration/language-processing/text-to-speech-amazon-polly.test.js @@ -0,0 +1,116 @@ +describe( '[Language Processing] Text to Speech (Amazon Polly) Tests', () => { + before( () => { + cy.login(); + cy.visit( + '/wp-admin/tools.php?page=classifai&tab=language_processing&feature=feature_text_to_speech_generation' + ); + cy.get( + '#classifai_feature_text_to_speech_generation_post_types_post' + ).check( 'post' ); + cy.get( '#provider' ).select( 'aws_polly' ); + cy.get( '#access_key_id' ).clear(); + cy.get( '#access_key_id' ).type( 'SAMPLE_ACCESS_KEY' ); + cy.get( '#secret_access_key' ).clear(); + cy.get( '#secret_access_key' ).type( 'SAMPLE_SECRET_ACCESS_KEY' ); + cy.get( '#aws_region' ).clear(); + cy.get( '#aws_region' ).type( 'SAMPLE_SECRET_ACCESS_KEY' ); + cy.get( '#status' ).check(); + cy.get( '#submit' ).click(); + + cy.get( '#voice' ).select( 'Aditi' ); + cy.get( '#submit' ).click(); + cy.optInAllFeatures(); + cy.disableClassicEditor(); + } ); + + beforeEach( () => { + cy.login(); + } ); + + it( 'Generates audio from text', () => { + cy.createPost( { + title: 'Text to Speech test', + content: + "This feature uses Amazon Polly's Text to Speech capabilities.", + } ); + + cy.get( 'button[aria-label="Close panel"]' ).click(); + cy.get( 'button[data-label="Post"]' ).click(); + cy.get( '.classifai-panel' ).click(); + cy.get( '#classifai-audio-controls__preview-btn' ).should( 'exist' ); + } ); + + it( 'Audio controls are visible if supported by post type', () => { + cy.visit( '/text-to-speech-test/' ); + cy.get( '.class-post-audio-controls' ).should( 'be.visible' ); + } ); + + it( 'a11y - aria-labels', () => { + cy.visit( '/text-to-speech-test/' ); + cy.get( '.dashicons-controls-play' ).should( 'be.visible' ); + cy.get( '.class-post-audio-controls' ).should( + 'have.attr', + 'aria-label', + 'Play audio' + ); + + cy.get( '.class-post-audio-controls' ).click(); + + cy.get( '.dashicons-controls-play' ).should( 'not.be.visible' ); + cy.get( '.class-post-audio-controls' ).should( + 'have.attr', + 'aria-label', + 'Pause audio' + ); + + cy.get( '.class-post-audio-controls' ).click(); + cy.get( '.dashicons-controls-play' ).should( 'be.visible' ); + cy.get( '.class-post-audio-controls' ).should( + 'have.attr', + 'aria-label', + 'Play audio' + ); + } ); + + it( 'a11y - keyboard accessibility', () => { + cy.visit( '/text-to-speech-test/' ); + cy.get( '.class-post-audio-controls' ) + .tab( { shift: true } ) + .tab() + .type( '{enter}' ); + cy.get( '.dashicons-controls-pause' ).should( 'be.visible' ); + cy.get( '.class-post-audio-controls' ).should( + 'have.attr', + 'aria-label', + 'Pause audio' + ); + + cy.get( '.class-post-audio-controls' ).type( '{enter}' ); + cy.get( '.dashicons-controls-play' ).should( 'be.visible' ); + cy.get( '.class-post-audio-controls' ).should( + 'have.attr', + 'aria-label', + 'Play audio' + ); + } ); + + it( 'Can see the enable button in a post (Classic Editor)', () => { + cy.enableClassicEditor(); + + cy.createClassicPost( { + title: 'Text to Speech test classic', + content: + "This feature uses Amazon Polly's Text to Speech capabilities.", + postType: 'post', + } ); + + cy.get( '#classifai-text-to-speech-meta-box' ).should( 'exist' ); + cy.get( '#classifai_synthesize_speech' ).check(); + cy.get( '#classifai-audio-preview' ).should( 'exist' ); + + cy.visit( '/text-to-speech-test/' ); + cy.get( '.class-post-audio-controls' ).should( 'be.visible' ); + + cy.disableClassicEditor(); + } ); +} ); diff --git a/tests/test-plugin/amazon-polly-voices.json b/tests/test-plugin/amazon-polly-voices.json new file mode 100644 index 000000000..ed459b5f7 --- /dev/null +++ b/tests/test-plugin/amazon-polly-voices.json @@ -0,0 +1,28 @@ +[ + { + "AdditionalLanguageCodes": [ + "hi-IN" + ], + "Gender": "Female", + "Id": "Aditi", + "LanguageCode": "en-IN", + "LanguageName": "Indian English", + "Name": "Aditi", + "SupportedEngines": [ + "standard", + "neural" + ] + }, + { + "AdditionalLanguageCodes": [], + "Gender": "Female", + "Id": "Danielle", + "LanguageCode": "en-US", + "LanguageName": "US English", + "Name": "Danielle", + "SupportedEngines": [ + "long-form", + "neural" + ] + } +] diff --git a/tests/test-plugin/e2e-test-plugin.php b/tests/test-plugin/e2e-test-plugin.php index c6ce7a891..12ee9baa1 100644 --- a/tests/test-plugin/e2e-test-plugin.php +++ b/tests/test-plugin/e2e-test-plugin.php @@ -6,6 +6,10 @@ // Mock the ClassifAI HTTP request calls and provide known response. add_filter( 'pre_http_request', 'classifai_test_mock_http_requests', 10, 3 ); +// Mock the AWS Polly API request calls and provide known response. +add_filter( 'classifai_aws_polly_pre_connect_to_service', 'classifai_mock_aws_polly_connect_to_service' ); +add_filter( 'classifai_aws_polly_pre_synthesize_speech', 'classifai_mock_aws_polly_pre_synthesize_speech' ); + /** * Mock ClassifAI's HTTP requests. * @@ -165,3 +169,14 @@ function () { ); } ); + +// AWS Polly API mock for connect to service. +function classifai_mock_aws_polly_connect_to_service() { + $voices = file_get_contents( __DIR__ . '/amazon-polly-voices.json' ); + return json_decode( $voices, true ); +} + +// AWS Polly API mock for synthesize speech. +function classifai_mock_aws_polly_pre_synthesize_speech() { + return file_get_contents( __DIR__ . '/text-to-speech.txt' ); +}