From 8fed7df2e2d7c3241245ceed027886cbe81c02b6 Mon Sep 17 00:00:00 2001 From: Edwin Takahashi Date: Mon, 28 Aug 2023 15:13:42 +0900 Subject: [PATCH] Jetpack E2E: add Social Connection spec using Tumblr. (#81073) * packages/calypso-e2e/src/secrets/types.ts packages/calypso-e2e/src/secrets/secrets-manager.ts packages/calypso-e2e/src/secrets/encrypted.enc - update secrets with new social connections category packages/calypso-e2e/src/lib/pages/marketing-page.ts - add methods to handle social connections packages/calypso-e2e/src/types/rest-api-client.types.ts - new methods to get and delete publicize connections test/e2e/specs/tools/social-connections__tumblr.ts - add new spec to connect and disconnect social connection * packages/calypso-e2e/src/lib/pages/marketing-page.ts - change return signature of validateSocialConnected method. * test/e2e/specs/tools/social-connections__tumblr.ts - replace Object.forEach with for...of loops * test/e2e/specs/tools/social-connections__tumblr.ts - replace sidebar navigation with direct visits to the page. packages/calypso-e2e/src/lib/pages/marketing-page.ts - add a `waitForLoadState` wait for the popup. * packages/calypso-e2e/src/rest-api-client.ts - add JSDoc * test/e2e/specs/tools/social-connections__tumblr.ts - add exception for private sites --- .../src/lib/pages/marketing-page.ts | 90 +++++++++++++++++- packages/calypso-e2e/src/rest-api-client.ts | 61 ++++++++++++ .../calypso-e2e/src/secrets/encrypted.enc | Bin 12896 -> 13040 bytes .../src/secrets/secrets-manager.ts | 6 ++ packages/calypso-e2e/src/secrets/types.ts | 6 ++ .../src/types/rest-api-client.types.ts | 12 +++ .../specs/tools/social-connections__tumblr.ts | 85 +++++++++++++++++ 7 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 test/e2e/specs/tools/social-connections__tumblr.ts diff --git a/packages/calypso-e2e/src/lib/pages/marketing-page.ts b/packages/calypso-e2e/src/lib/pages/marketing-page.ts index 5822c3025ef6a..44e77badd10c2 100644 --- a/packages/calypso-e2e/src/lib/pages/marketing-page.ts +++ b/packages/calypso-e2e/src/lib/pages/marketing-page.ts @@ -1,6 +1,15 @@ import { Page } from 'playwright'; +import { getCalypsoURL } from '../../data-helper'; import { clickNavTab } from '../../element-helper'; +type MarketingPageTab = + | 'Marketing Tools' + | 'Traffic' + | 'Connections' + | 'Sharing Buttons' + | 'Business Tools'; +type SocialConnection = 'Facebook' | 'LinkedIn' | 'Tumblr' | 'Mastodon' | 'Instagram Business'; + const selectors = { // Traffic tab websiteMetaTextArea: '#advanced_seo_front_page_description', @@ -25,12 +34,20 @@ export class MarketingPage { } /** - * Given a string, clicks on the tab matching the string at top of the page. + * Navigates directly to the Marketing page for the site. * - * @param {string} name Name of the tab to click on the top of the page. - * @returns {Promise} No return value. + * @param {string} siteSlug Site slug. + */ + async visit( siteSlug: string ) { + await this.page.goto( getCalypsoURL( `marketing/tools/${ siteSlug }` ) ); + } + + /** + * Click on the tab name matching the given parameter `name`. + * + * @param {MarketingPageTab} name Name of the tab to click on the top of the page. */ - async clickTab( name: string ): Promise< void > { + async clickTab( name: MarketingPageTab ) { await clickNavTab( this.page, name ); } @@ -66,4 +83,69 @@ export class MarketingPage { await this.page.click( selectors.seoPreviewPaneCloseButton ); await this.page.waitForSelector( selectors.seoPreviewButton ); } + + /* Social Connectisons */ + + /** + * Clicks on the Connection button for specified Social service. + * + * @param {SocialConnection} target Social service. + */ + async clickSocialConnectButton( target: SocialConnection ): Promise< Page > { + // Set up a handler for the popup promise. + const popupPromise = this.page.waitForEvent( 'popup' ); + + await this.page + .getByRole( 'main' ) + .getByRole( 'listitem' ) + .filter( { hasText: target } ) + .getByRole( 'button', { name: 'Connect' } ) + .click(); + + return await popupPromise; + } + + /** + * Validates the specified Social service button now is connected. + * + * @param {SocialConnection} target Social service. + * @throws {Error} If the social connection was not made for any reason. + */ + async validateSocialConnected( target: SocialConnection ): Promise< void > { + await this.page + .getByRole( 'main' ) + .getByRole( 'listitem' ) + .filter( { hasText: target } ) + .getByRole( 'button', { name: 'Disconnect' } ) + .waitFor(); + } + + /** + * Tailored method to set up the Tumblr connection. + * + * @param {Page} popup Pointer to the popup Page object. + * @param param1 Keyed object parameter. + * @param {string} param1.username Tumblr username. + * @param {string} param1.password Tumblr password. + */ + async setupTumblr( popup: Page, { username, password }: { username: string; password: string } ) { + // Wait for the page load to complete. Otherwise, a `Cannot POST /login` error + // is shown. + await popup.waitForLoadState( 'networkidle' ); + + // Fill in the email and password. + await popup.getByRole( 'textbox', { name: 'email' } ).fill( username ); + await popup.getByPlaceholder( 'Password' ).fill( password ); + + // Log in. + await popup.getByRole( 'button', { name: 'Log in' } ).click(); + + // Click on Tumblr side's "Allow" button. + const popupClosePromise = popup.waitForEvent( 'close' ); + await popup.getByRole( 'button', { name: 'Allow' } ).click(); + await popupClosePromise; + + // Click on the Calypso side's "Connect" button. + await this.page.getByRole( 'dialog' ).getByRole( 'button', { name: 'Connect' } ).click(); + } } diff --git a/packages/calypso-e2e/src/rest-api-client.ts b/packages/calypso-e2e/src/rest-api-client.ts index 37d34bce1da21..799804b293cb2 100644 --- a/packages/calypso-e2e/src/rest-api-client.ts +++ b/packages/calypso-e2e/src/rest-api-client.ts @@ -9,6 +9,8 @@ import { PluginParams, AllDomainsResponse, DomainData, + PublicizeConnectionDeletedResponse, + PublicizeConnection, } from './types'; import type { Roles } from './lib'; import type { @@ -1132,4 +1134,63 @@ export class RestAPIClient { return response; } + + /* Publicize */ + + /** + * Returns an array of existing publicize (social) connections. + * + * @param {number} siteID Site ID. + * @returns {Promise>} Array of Publicize connections. + */ + async getAllPublicizeConnections( siteID: number ): Promise< Array< PublicizeConnection > > { + const params: RequestParams = { + method: 'get', + headers: { + Authorization: await this.getAuthorizationHeader( 'bearer' ), + 'Content-Type': this.getContentTypeHeader( 'json' ), + }, + }; + + const response = await this.sendRequest( + this.getRequestURL( '1.1', `/sites/${ siteID }/publicize-connections` ), + params + ); + + if ( response.hasOwnProperty( 'error' ) ) { + throw new Error( + `${ ( response as ErrorResponse ).error }: ${ ( response as ErrorResponse ).message }` + ); + } + + return response[ 'connections' ]; + } + + /** + * Given siteID and connectionID, deletes the connection. + * + * @param {number} siteID Site ID. + * @param {number} connectionID Publicize connection ID. + * @returns {Promise} Confirmation of connection being deleted. + */ + async deletePublicizeConnection( + siteID: number, + connectionID: number + ): Promise< PublicizeConnectionDeletedResponse > { + const params: RequestParams = { + method: 'post', + headers: { + Authorization: await this.getAuthorizationHeader( 'bearer' ), + 'Content-Type': this.getContentTypeHeader( 'json' ), + }, + }; + + return await this.sendRequest( + this.getRequestURL( + '1.1', + `/sites/${ siteID }/publicize-connections/${ connectionID }/delete` + ), + params + ); + } } diff --git a/packages/calypso-e2e/src/secrets/encrypted.enc b/packages/calypso-e2e/src/secrets/encrypted.enc index 251ffa5b17b0c436428a5ef4bf97ad7ae5347d65..af99d41ebc89dc78990edba4937d3d886238f6e5 100644 GIT binary patch literal 13040 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�Bk3n8TP!V!9f=*rGidjf^6~mzDClX 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 literal 12896 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 KU;zJJMLkSA3gvqM diff --git a/packages/calypso-e2e/src/secrets/secrets-manager.ts b/packages/calypso-e2e/src/secrets/secrets-manager.ts index 0b44e3b9d8856..0c11b0e8d4f6d 100644 --- a/packages/calypso-e2e/src/secrets/secrets-manager.ts +++ b/packages/calypso-e2e/src/secrets/secrets-manager.ts @@ -163,6 +163,12 @@ export class SecretsManager { martechTosUploadCredentials: { bearer_token: 'FAKE_VALUE', }, + socialAccounts: { + tumblr: { + username: 'FAKE_VALUE', + password: 'FAKE_VALUE', + }, + }, mailosaur: { apiKey: 'FAKE_VALUE', inviteInboxId: 'FAKE_VALUE', diff --git a/packages/calypso-e2e/src/secrets/types.ts b/packages/calypso-e2e/src/secrets/types.ts index 53878e73a3deb..354d959a8894f 100644 --- a/packages/calypso-e2e/src/secrets/types.ts +++ b/packages/calypso-e2e/src/secrets/types.ts @@ -37,6 +37,12 @@ export interface Secrets { martechTosUploadCredentials: { bearer_token: string; }; + socialAccounts: { + tumblr: { + username: string; + password: string; + }; + }; mailosaur: { apiKey: string; inviteInboxId: string; diff --git a/packages/calypso-e2e/src/types/rest-api-client.types.ts b/packages/calypso-e2e/src/types/rest-api-client.types.ts index f4bb2e947d720..7f7b961e4a902 100644 --- a/packages/calypso-e2e/src/types/rest-api-client.types.ts +++ b/packages/calypso-e2e/src/types/rest-api-client.types.ts @@ -198,6 +198,18 @@ export interface JetpackSearchResponse { // Lots more of course -- add as needed! } +export interface PublicizeConnection { + ID: number; + site_ID: number; + label: string; + external_ID: string; +} + +export interface PublicizeConnectionDeletedResponse { + ID: number; + deleted: boolean; +} + /* Error Responses */ export interface BearerTokenErrorResponse { diff --git a/test/e2e/specs/tools/social-connections__tumblr.ts b/test/e2e/specs/tools/social-connections__tumblr.ts new file mode 100644 index 0000000000000..459e1c81a0236 --- /dev/null +++ b/test/e2e/specs/tools/social-connections__tumblr.ts @@ -0,0 +1,85 @@ +/** + * @group jetpack-wpcom-integration + */ + +import { + envToFeatureKey, + getTestAccountByFeature, + envVariables, + DataHelper, + MarketingPage, + RestAPIClient, + TestAccount, + SecretsManager, +} from '@automattic/calypso-e2e'; +import { Page, Browser } from 'playwright'; +import { skipDescribeIf } from '../../jest-helpers'; + +declare const browser: Browser; + +/** + * Sets up a Tumblr social connection for the site. + * + * Note, Private sites do not support Social/Publicize connections. + * + * Keywords: Social Connections, Marketing, Jetpack, Tumblr, Publicize + */ +skipDescribeIf( envVariables.ATOMIC_VARIATION === 'private' )( + DataHelper.createSuiteTitle( 'Social Connections: Set up Tumblr' ), + function () { + let page: Page; + let popup: Page; + + let testAccount: TestAccount; + let restAPIClient: RestAPIClient; + let marketingPage: MarketingPage; + + beforeAll( async () => { + page = await browser.newPage(); + + const features = envToFeatureKey( envVariables ); + const accountName = getTestAccountByFeature( features ); + testAccount = new TestAccount( accountName ); + await testAccount.authenticate( page ); + + restAPIClient = new RestAPIClient( testAccount.credentials ); + + // Check whether a Tumblr connection exists. + const connections = await restAPIClient.getAllPublicizeConnections( + testAccount.credentials.testSites?.primary.id as number + ); + + // If it does, remove the connection. + for ( const connection of connections ) { + if ( connection.label === 'Tumblr' ) { + console.info( + `Removing existing connection for Tumblr for accountName ${ accountName }.` + ); + await restAPIClient.deletePublicizeConnection( connection.site_ID, connection.ID ); + } + } + + marketingPage = new MarketingPage( page ); + } ); + + it( 'Navigate to Tools > Marketing page', async function () { + await marketingPage.visit( testAccount.getSiteURL( { protocol: false } ) ); + } ); + + it( 'Click on Connections tab', async function () { + await marketingPage.clickTab( 'Connections' ); + } ); + + it( 'Click on the "Connect" button for Tumblr', async function () { + popup = await marketingPage.clickSocialConnectButton( 'Tumblr' ); + } ); + + it( 'Set up Tumblr', async function () { + await marketingPage.setupTumblr( popup, SecretsManager.secrets.socialAccounts.tumblr ); + } ); + + it( 'Tumblr is connected', async function () { + await marketingPage.validateSocialConnected( 'Tumblr' ); + } ); + } +);