Skip to content

Commit c0ef967

Browse files
committed
Added e2e test for email and sms opt-in checkboxes
Added sms and email opt-in e2e tests for sitegen Moved global variables to module Added unit test for subscriptions Refactored order confirmation unit test Setup mock for KlaviyoSubscribeProfilesService Refactor Site and LocalServiceRegistry Mocks Completed subscriber tests
1 parent 57995e2 commit c0ef967

14 files changed

Lines changed: 375 additions & 123 deletions

test/src/tests/e2e/sfra/checkout/checkout-tests.spec.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,34 @@ test.describe('Test Klaviyo add to cart event', () => {
5454
})
5555
})
5656

57-
test.describe('Test Klaviyo order confirmation event', () => {
58-
test('Complete purchase and verify event data', async ({ page }) => {
59-
const resultMsg = 'Klaviyo Service Result:'
57+
test.describe('Test Klaviyo sms signup', () => {
58+
test('Verify sms checkbox present and selectable', async ({ page }) => {
6059
email = await checkoutPage.generateEmail()
6160
testData.email = email
6261
await checkoutPage.productPage.getProduct()
6362
await checkoutPage.productPage.addToCart()
6463
await checkoutPage.startCheckout()
6564
await checkoutPage.enterGuestEmail(email)
65+
await checkoutPage.selectSMS()
6666
await checkoutPage.fillShippingForm(testData)
6767
await checkoutPage.fillPaymentForm(paymentData)
6868
await page.waitForTimeout(3000)
6969
expect(await page.innerText('h1.page-title')).toBe('Thank You')
7070
})
71-
})
71+
})
72+
73+
test.describe('Test Klaviyo email signup', () => {
74+
test('Verify email checkbox present and selectable', async ({ page }) => {
75+
email = await checkoutPage.generateEmail()
76+
testData.email = email
77+
await checkoutPage.productPage.getProduct()
78+
await checkoutPage.productPage.addToCart()
79+
await checkoutPage.startCheckout()
80+
await checkoutPage.enterGuestEmail(email)
81+
await checkoutPage.selectEmail()
82+
await checkoutPage.fillShippingForm(testData)
83+
await checkoutPage.fillPaymentForm(paymentData)
84+
await page.waitForTimeout(3000)
85+
expect(await page.innerText('h1.page-title')).toBe('Thank You')
86+
})
87+
})

test/src/tests/e2e/sfra/page-objects/checkout.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,16 @@ exports.CheckoutPage = class CheckoutPage extends BasePage {
7878
await this.placeOrderLocator.click()
7979
await this.page.waitForLoadState('networkidle')
8080
}
81-
}
81+
82+
async selectSMS() {
83+
const boxes = await this.page.locator('#KLSmsSubscribe')
84+
await boxes.first().click()
85+
expect(boxes.first()).toBeChecked()
86+
}
87+
88+
async selectEmail() {
89+
const boxes = await this.page.locator('#KLEmailSubscribe')
90+
await boxes.first().click()
91+
expect(boxes.first()).toBeChecked()
92+
}
93+
}

test/src/tests/e2e/sfra/product/product-tests.spec.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { test, expect } from '@playwright/test'
22
import { ProductPage } from '../page-objects/product.js'
33
import { getLatestMetricData } from '../../../../utils/v3-api-helper.mjs'
4+
import * as dotenv from 'dotenv'
5+
6+
dotenv.config()
7+
8+
const { KLAVIYO_SFRA_PRIVATE_KEY } = process.env
49

510
let testData = {
611
firstName: 'Product',
@@ -46,13 +51,17 @@ test.describe('Test Klaviyo viewed category event', () => {
4651

4752
test.describe('Test successful integration with Klaviyo', () => {
4853
test('Verify Viewed Product metric in Klaviyo sandbox', async ({ page }) => {
54+
const apiParams = {
55+
method: 'GET',
56+
apiKey: KLAVIYO_SFRA_PRIVATE_KEY
57+
}
4958
email = await productPage.generateEmail()
5059
testData.email = email
5160
await productPage.accountPage.gotoAccountLogin()
5261
await productPage.accountPage.fillRegistrationForm(testData)
5362
expect(await page.innerText('h1.page-title')).toBe('Dashboard')
5463
await productPage.getProduct()
55-
const metrics = await getLatestMetricData()
64+
const metrics = await getLatestMetricData(apiParams)
5665
const metricName = metrics.attributes.name
5766
expect(metricName).toBe('Viewed Product')
5867
})

test/src/tests/e2e/sitegen/checkout/checkout-tests.spec.js

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,38 @@ test.describe('Test Klaviyo add to cart event', () => {
3939
await checkoutPage.productPage.addToCart()
4040
expect(logData[0].success).toBe(true)
4141
})
42-
})
42+
})
43+
44+
test.describe('Test Klaviyo sms signup', () => {
45+
test('Verify sms checkbox present and selectable', async ({ page }) => {
46+
email = await checkoutPage.generateEmail()
47+
testData.email = email
48+
await checkoutPage.productPage.getProduct()
49+
await checkoutPage.productPage.addToCart()
50+
await checkoutPage.startCheckout()
51+
await checkoutPage.checkoutAsGuest()
52+
await checkoutPage.fillShippingForm(testData)
53+
await checkoutPage.selectSMS()
54+
await checkoutPage.fillBillingForm(email)
55+
await checkoutPage.fillPaymentForm(paymentData)
56+
await page.waitForTimeout(3000)
57+
expect(await checkoutPage.orderSuccessMessage.innerText().valueOf()).toBe('Thank you for your order.')
58+
})
59+
})
60+
61+
test.describe('Test Klaviyo email signup', () => {
62+
test('Verify email checkbox present and selectable', async ({ page }) => {
63+
email = await checkoutPage.generateEmail()
64+
testData.email = email
65+
await checkoutPage.productPage.getProduct()
66+
await checkoutPage.productPage.addToCart()
67+
await checkoutPage.startCheckout()
68+
await checkoutPage.checkoutAsGuest()
69+
await checkoutPage.fillShippingForm(testData)
70+
await checkoutPage.selectEmail()
71+
await checkoutPage.fillBillingForm(email)
72+
await checkoutPage.fillPaymentForm(paymentData)
73+
await page.waitForTimeout(3000)
74+
expect(await checkoutPage.orderSuccessMessage.innerText().valueOf()).toBe('Thank you for your order.')
75+
})
76+
})

test/src/tests/e2e/sitegen/page-objects/checkout.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ exports.CheckoutPage = class CheckoutPage extends BasePage {
1414
this.productPage = new ProductPage(page, isMobile)
1515
this.accountPage = new AccountPage(page, isMobile)
1616

17-
this.guestCheckoutBtn = 'dwfrm_login_unregistered'
18-
1917
// Shipping form
2018
this.shippingFnameLocator = page.locator('#dwfrm_singleshipping_shippingAddress_addressFields_firstName')
2119
this.shippingLnameLocator = page.locator('#dwfrm_singleshipping_shippingAddress_addressFields_lastName')
@@ -51,6 +49,10 @@ exports.CheckoutPage = class CheckoutPage extends BasePage {
5149
await this.guestCheckoutSubmit.click()
5250
}
5351

52+
async checkoutAsGuest() {
53+
await this.page.locator('button[value="Checkout as Guest"]').click()
54+
}
55+
5456
async fillShippingForm(data) {
5557
await this.shippingFnameLocator.fill(data.firstName)
5658
await this.shippingLnameLocator.fill(data.lastName)
@@ -63,13 +65,12 @@ exports.CheckoutPage = class CheckoutPage extends BasePage {
6365
await this.stateLocator.selectOption({ value: data.state })
6466
await this.phoneLocator.fill(data.phone)
6567
await this.sameAsLocator.click()
66-
// await this.submitShippingLocator.click()
6768
await this.page.getByRole('button', { name: 'Continue to Billing >' }).click()
6869
}
6970

70-
async fillBillingForm(data) {
71+
async fillBillingForm(email) {
7172
await this.billingEmailLocator.isVisible()
72-
await this.billingEmailLocator.fill(data.email)
73+
await this.billingEmailLocator.fill(email)
7374
}
7475

7576
async fillPaymentForm(data) {
@@ -88,4 +89,16 @@ exports.CheckoutPage = class CheckoutPage extends BasePage {
8889
await this.page.getByRole('button', { name: 'Place Order' }).click()
8990
await this.page.waitForLoadState('networkidle')
9091
}
91-
}
92+
93+
async selectSMS() {
94+
const boxes = await this.page.locator('#KLSmsSubscribe')
95+
await boxes.first().click()
96+
expect(boxes.first()).toBeChecked()
97+
}
98+
99+
async selectEmail() {
100+
const boxes = await this.page.locator('#KLEmailSubscribe')
101+
await boxes.first().click()
102+
expect(boxes.first()).toBeChecked()
103+
}
104+
}
Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,57 @@
1-
const sinon = require('sinon');
1+
const Service = require('./util/service')
2+
const responseDataMock = require('./util/responseDataMock')
23

3-
const KlaviyoEventService = {
4+
getResponse = (requestBody) => {
5+
let phone
6+
let response = {}
7+
const dataObj = requestBody.data.attributes.subscriptions[0]
8+
phone = dataObj.phone_number
49

5-
call: sinon.stub(),
6-
createRequest: sinon.stub(),
7-
parseResponse: sinon.stub(),
8-
getRequestLogMessage: sinon.stub(),
9-
getResponseLogMessage: sinon.stub(),
10+
// Case 1: Subscribe request is made to Klaviyo to the email channel, including both email and phone number. Response is successful (202)
11+
if (dataObj.email && phone) {
12+
response.statusCode = 202,
13+
response.errorText = null,
14+
response.statusMessage = 'success',
15+
response.text = responseDataMock.subscribeSuccessMock
16+
// Case 1: Subscribe request is made to Klaviyo to the email channel, including both email and phone_number is null. Response is successful (202)
17+
} else if (dataObj.email && phone === null) {
18+
response.statusCode = 202,
19+
response.errorText = null,
20+
response.statusMessage = 'success',
21+
response.text = responseDataMock.subscribeSuccessMock
22+
// Case 2: Subscribe request is made to Klaviyo to the email channel, including both email and phone number. Response is not successful (400) and response contains an error message indicating phone number was invalid:
23+
} else if (dataObj.email && phone === undefined) {
24+
response.statusCode = 400,
25+
response.errorText = 'The phone number provided either does not exist or is ineligible to receive SMS',
26+
response.statusMessage = 'error',
27+
response.text = responseDataMock.invalidPhoneErrorMock
28+
// Case 3: Subscribe request is made to Klaviyo to the email channel, including both email and phone number. Response is not not successful (400) and response does not contain an error message indicating phone number was invalid:
29+
} else {
30+
response.statusCode = 400,
31+
response.errorText = 'Some other error occurred',
32+
response.statusMessage = 'error',
33+
response.text = responseDataMock.otherErrorMock
34+
}
35+
36+
return response
37+
}
1038

11-
createService(svc) {
39+
class ServiceRegistry {
40+
createService(serviceId, fn) {
41+
const svc = new Service(serviceId)
1242
return {
13-
svc,
14-
call: this.call.returns({
15-
status: 'OK'
16-
}),
17-
createRequest: this.createRequest
43+
call: (requestBody) => {
44+
fn.createRequest(svc, requestBody)
45+
const response = getResponse(requestBody)
46+
const parsedResponse = fn.parseResponse(svc, response)
47+
48+
fn.getRequestLogMessage(requestBody)
49+
fn.getResponseLogMessage(response)
50+
51+
return parsedResponse
52+
},
1853
}
1954
}
2055
}
2156

22-
module.exports = KlaviyoEventService
57+
module.exports = new ServiceRegistry

test/src/tests/mocks/dw.system.Site.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
let mockPreferences = {
22
klaviyo_api_key: 'ababababababababab',
3-
klaviyo_sendEventsAsSFCC: 'demandware'
3+
klaviyo_sendEventsAsSFCC: 'demandware',
4+
klaviyo_email_list_id: 'AbAbs',
5+
klaviyo_sms_list_id: 'UuDdLr'
46
}
57

68
const preferences = {}
@@ -14,7 +16,6 @@ const Site = {
1416
if (Object.prototype.hasOwnProperty.call(mockPreferences, key)) {
1517
return mockPreferences[key];
1618
}
17-
1819
return preferences[key]
1920
}
2021
},
@@ -42,7 +43,3 @@ const restore = () => {
4243
module.exports = Site
4344
module.exports.setMockPreferenceValue = setMockPreferenceValue
4445
module.exports.restore = restore
45-
46-
Object.defineProperty(module.exports, 'preferences', {
47-
get: () => Object.assign({}, preferences, mockPreferences)
48-
})
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
const getServiceData = ((id) => {
2+
if (id === 'KlaviyoSubscribeProfilesService') {
3+
return {
4+
id: id
5+
}
6+
} else if ('KlaviyoEventService') {
7+
return {
8+
id: id
9+
}
10+
}
11+
})
12+
13+
class Service {
14+
constructor(id, method) {
15+
this.ID = id
16+
this.headers = {}
17+
this.args = {}
18+
this.configuration = getServiceData(id)
19+
}
20+
21+
addHeader(name, value) {
22+
this.headers[name] = value
23+
}
24+
25+
setRequestMethod(method) {
26+
this.method = method
27+
}
28+
29+
setURL(url) {
30+
this.url = url
31+
}
32+
33+
addParam(name, value) {
34+
this.args[name] = value
35+
}
36+
}
37+
38+
module.exports = Service
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const globalMocks = () => {
2+
3+
global.session = {
4+
getCurrency: function() {
5+
return {
6+
getCurrencyCode: function() {
7+
return 'USD'
8+
}
9+
}
10+
},
11+
custom: {
12+
KLEmailSubscribe: true,
13+
KLSmsSubscribe: true
14+
}
15+
}
16+
17+
global.dw = {
18+
util: {
19+
StringUtils: {
20+
formatMoney: function () {
21+
return '$9.99'
22+
},
23+
formatCalendar: function () {
24+
return '2022-22-02'
25+
}
26+
},
27+
Calendar: function() {
28+
return '2022-22-02'
29+
}
30+
},
31+
value: {
32+
Money: function() {
33+
return '$9.00'
34+
}
35+
},
36+
}
37+
38+
}
39+
40+
module.exports = globalMocks

0 commit comments

Comments
 (0)