@meetelise/chat 1.51.0 → 1.51.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,253 @@
1
+ import { expect } from "@esm-bundle/chai";
2
+ import "../public/dist/index";
3
+ import type {
4
+ InternationalPhoneChangeDetail,
5
+ InternationalPhoneInput,
6
+ } from "./WebComponent/actions/international-phone-input";
7
+ import type { EmailUsWindow } from "./WebComponent/actions/email-us-window";
8
+ import type { CallUsWindow } from "./WebComponent/actions/call-us-window";
9
+
10
+ describe("international-phone-input", () => {
11
+ let phoneInput: InternationalPhoneInput;
12
+
13
+ beforeEach(async () => {
14
+ if (!customElements.get("international-phone-input")) {
15
+ throw new Error("Expected international-phone-input to be registered");
16
+ }
17
+ phoneInput = document.createElement(
18
+ "international-phone-input"
19
+ ) as InternationalPhoneInput;
20
+ phoneInput.country = "US";
21
+ document.body.appendChild(phoneInput);
22
+ await phoneInput.updateComplete;
23
+ });
24
+
25
+ afterEach(() => {
26
+ phoneInput.remove();
27
+ });
28
+
29
+ it("infers the country and E.164 value when an international number is pasted", async () => {
30
+ let detail: InternationalPhoneChangeDetail | null = null;
31
+ phoneInput.addEventListener("phone-change", (event) => {
32
+ detail = (event as CustomEvent<InternationalPhoneChangeDetail>).detail;
33
+ });
34
+ const input = phoneInput.shadowRoot?.querySelector("input");
35
+ if (!input) throw new Error("Expected phone input");
36
+
37
+ input.value = "+44 7400 123456";
38
+ input.setSelectionRange(input.value.length, input.value.length);
39
+ input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
40
+ await phoneInput.updateComplete;
41
+
42
+ expect(phoneInput.e164).to.equal("+447400123456");
43
+ expect(phoneInput.isValid).to.equal(true);
44
+ expect(
45
+ phoneInput.shadowRoot?.querySelector<HTMLSelectElement>("select")?.value
46
+ ).to.equal("GB");
47
+ expect(detail).to.deep.include({
48
+ country: "GB",
49
+ e164: "+447400123456",
50
+ isValid: true,
51
+ });
52
+ });
53
+
54
+ it("uses the building country for national input", async () => {
55
+ phoneInput.country = "GB";
56
+ await phoneInput.updateComplete;
57
+ expect(
58
+ phoneInput.shadowRoot?.querySelector<HTMLSelectElement>("select")?.value
59
+ ).to.equal("GB");
60
+ const input = phoneInput.shadowRoot?.querySelector("input");
61
+ if (!input) throw new Error("Expected phone input");
62
+
63
+ input.value = "07400123456";
64
+ input.setSelectionRange(input.value.length, input.value.length);
65
+ input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
66
+ await phoneInput.updateComplete;
67
+
68
+ expect(phoneInput.value).to.equal("07400 123456");
69
+ expect(phoneInput.e164).to.equal("+447400123456");
70
+ });
71
+
72
+ it("displays a non-US building country on the first render", async () => {
73
+ phoneInput.remove();
74
+ phoneInput = document.createElement(
75
+ "international-phone-input"
76
+ ) as InternationalPhoneInput;
77
+ phoneInput.country = "GB";
78
+ document.body.appendChild(phoneInput);
79
+ await phoneInput.updateComplete;
80
+
81
+ expect(
82
+ phoneInput.shadowRoot?.querySelector<HTMLSelectElement>("select")?.value
83
+ ).to.equal("GB");
84
+ });
85
+
86
+ it("retains existing US behavior by default", async () => {
87
+ const input = phoneInput.shadowRoot?.querySelector("input");
88
+ if (!input) throw new Error("Expected phone input");
89
+
90
+ input.value = "2025550123";
91
+ input.setSelectionRange(input.value.length, input.value.length);
92
+ input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
93
+ await phoneInput.updateComplete;
94
+
95
+ expect(phoneInput.value).to.equal("(202) 555-0123");
96
+ expect(phoneInput.e164).to.equal("+12025550123");
97
+ });
98
+
99
+ it("uses a compact selected-country label while keeping full menu labels", async () => {
100
+ const select = phoneInput.shadowRoot?.querySelector("select");
101
+ if (!select) throw new Error("Expected country select");
102
+ select.value = "MX";
103
+ select.dispatchEvent(new Event("change", { bubbles: true }));
104
+ await phoneInput.updateComplete;
105
+
106
+ expect(
107
+ phoneInput.shadowRoot?.querySelector(".country-select-label")?.textContent
108
+ ).to.contain("🇲🇽 +52");
109
+ expect(select.selectedOptions[0].textContent).to.contain("🇲🇽 +52 – Mexico");
110
+ });
111
+
112
+ it("deletes the preceding digit when backspacing over formatting", async () => {
113
+ const input = phoneInput.shadowRoot?.querySelector("input");
114
+ if (!input) throw new Error("Expected phone input");
115
+ input.value = "2025550123";
116
+ input.setSelectionRange(input.value.length, input.value.length);
117
+ input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
118
+ await phoneInput.updateComplete;
119
+
120
+ input.setSelectionRange(5, 5);
121
+ input.dispatchEvent(
122
+ new KeyboardEvent("keydown", {
123
+ key: "Backspace",
124
+ bubbles: true,
125
+ composed: true,
126
+ cancelable: true,
127
+ })
128
+ );
129
+ await phoneInput.updateComplete;
130
+
131
+ expect(phoneInput.value).to.equal("(205) 550-123");
132
+ expect(input.selectionStart).to.equal(3);
133
+ });
134
+
135
+ it("keeps the caret at the start when input is reformatted", async () => {
136
+ const input = phoneInput.shadowRoot?.querySelector("input");
137
+ if (!input) throw new Error("Expected phone input");
138
+ input.value = "2025550123";
139
+ input.setSelectionRange(0, 0);
140
+
141
+ input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
142
+ await phoneInput.updateComplete;
143
+
144
+ expect(phoneInput.value).to.equal("(202) 555-0123");
145
+ expect(input.selectionStart).to.equal(0);
146
+ });
147
+
148
+ it("preserves an international prefix when backspacing over formatting", async () => {
149
+ const input = phoneInput.shadowRoot?.querySelector("input");
150
+ if (!input) throw new Error("Expected phone input");
151
+ input.value = "+44 7400 123456";
152
+ input.setSelectionRange(input.value.length, input.value.length);
153
+ input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
154
+ await phoneInput.updateComplete;
155
+
156
+ input.setSelectionRange(9, 9);
157
+ input.dispatchEvent(
158
+ new KeyboardEvent("keydown", {
159
+ key: "Backspace",
160
+ bubbles: true,
161
+ composed: true,
162
+ cancelable: true,
163
+ })
164
+ );
165
+ await phoneInput.updateComplete;
166
+
167
+ expect(phoneInput.value.startsWith("+")).to.equal(true);
168
+ expect(phoneInput.value.replace(/\D/g, "")).to.equal("44740123456");
169
+ expect(input.selectionStart).to.equal(6);
170
+ });
171
+
172
+ it("allows backspace to remove the leading international prefix", async () => {
173
+ const input = phoneInput.shadowRoot?.querySelector("input");
174
+ if (!input) throw new Error("Expected phone input");
175
+ input.value = "+";
176
+ input.setSelectionRange(1, 1);
177
+ const keydown = new KeyboardEvent("keydown", {
178
+ key: "Backspace",
179
+ bubbles: true,
180
+ composed: true,
181
+ cancelable: true,
182
+ });
183
+
184
+ input.dispatchEvent(keydown);
185
+
186
+ expect(keydown.defaultPrevented).to.equal(false);
187
+ input.value = "";
188
+ input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
189
+ await phoneInput.updateComplete;
190
+ expect(phoneInput.value).to.equal("");
191
+ expect(phoneInput.e164).to.equal(null);
192
+ });
193
+ });
194
+
195
+ it("normalizes international numbers through the Email Us form", async () => {
196
+ const emailUs = document.createElement("email-us-window") as EmailUsWindow;
197
+ emailUs.country = "GB";
198
+ document.body.appendChild(emailUs);
199
+ await emailUs.updateComplete;
200
+
201
+ const phoneInput = emailUs.shadowRoot?.querySelector<InternationalPhoneInput>(
202
+ "international-phone-input"
203
+ );
204
+ expect(phoneInput).to.exist;
205
+ expect(phoneInput?.country).to.equal("GB");
206
+ const input = phoneInput?.shadowRoot?.querySelector("input");
207
+ if (!phoneInput || !input) throw new Error("Expected phone input");
208
+
209
+ input.value = "07400123456";
210
+ input.setSelectionRange(input.value.length, input.value.length);
211
+ input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
212
+ await phoneInput.updateComplete;
213
+ await emailUs.updateComplete;
214
+
215
+ expect(emailUs.phoneNumber).to.equal("07400 123456");
216
+ expect(emailUs.phoneNumberE164).to.equal("+447400123456");
217
+ expect(emailUs.phoneCountry).to.equal("GB");
218
+
219
+ emailUs.firstName = "Local";
220
+ emailUs.lastName = "Test";
221
+ emailUs.email = "local.test@example.com";
222
+ emailUs.validateFormFields();
223
+ expect(emailUs.hasPhoneNumberError).to.equal(false);
224
+
225
+ emailUs.remove();
226
+ });
227
+
228
+ it("keeps Text Us on the existing US-only phone input", async () => {
229
+ const callUs = document.createElement("call-us-window") as CallUsWindow;
230
+ callUs.hasTextUsEnabled = "true";
231
+ document.body.appendChild(callUs);
232
+ await callUs.updateComplete;
233
+
234
+ expect(callUs.shadowRoot?.querySelector("international-phone-input")).to.not
235
+ .exist;
236
+ expect(
237
+ callUs.shadowRoot?.querySelector('[aria-label="Country calling code"]')
238
+ ).to.not.exist;
239
+
240
+ const input = callUs.shadowRoot?.querySelector<HTMLInputElement>(
241
+ 'input[placeholder="Enter phone"]'
242
+ );
243
+ if (!input) throw new Error("Expected Text Us phone input");
244
+ input.value = "2025550123";
245
+ input.dispatchEvent(new KeyboardEvent("keyup", { bubbles: true }));
246
+ await callUs.updateComplete;
247
+
248
+ expect(callUs.phoneNumberToText).to.equal("(202) 555-0123");
249
+ expect(input.value).to.equal("(202) 555-0123");
250
+ expect(input.maxLength).to.equal(14);
251
+
252
+ callUs.remove();
253
+ });
@@ -0,0 +1,145 @@
1
+ import { expect } from "@esm-bundle/chai";
2
+ import { restore, useFakeXMLHttpRequest } from "sinon/pkg/sinon-esm";
3
+ import "../public/dist/index";
4
+ import type { EmailUsWindow } from "./WebComponent/actions/email-us-window";
5
+ import type {
6
+ TourScheduler,
7
+ TourType,
8
+ } from "./WebComponent/Scheduler/tour-scheduler";
9
+
10
+ type TourSubmissionHarness = {
11
+ tourType: TourType;
12
+ selectedDate: Date;
13
+ selectedTime: { datetime: string; offset: string };
14
+ phoneNumber: string;
15
+ phoneNumberE164: string | null;
16
+ email: string;
17
+ };
18
+
19
+ type FakeRequest = XMLHttpRequest & {
20
+ requestBody?: string;
21
+ respond: (
22
+ status: number,
23
+ headers?: Record<string, string>,
24
+ body?: string
25
+ ) => void;
26
+ url: string;
27
+ };
28
+
29
+ const guidedTour = "guided" as TourType;
30
+
31
+ afterEach(() => {
32
+ restore();
33
+ window.dataLayer = [];
34
+ });
35
+
36
+ it("submits the canonical international number in the Email Us request", async () => {
37
+ const fakeXhr = useFakeXMLHttpRequest();
38
+ const requests: FakeRequest[] = [];
39
+ fakeXhr.onCreate = (request: FakeRequest) => requests.push(request);
40
+ const emailUs = document.createElement("email-us-window") as EmailUsWindow;
41
+ Object.assign(emailUs, {
42
+ firstName: "Local",
43
+ lastName: "Test",
44
+ email: "local.test@example.com",
45
+ phoneNumber: "07400 123456",
46
+ phoneNumberE164: "+447400123456",
47
+ message: "I would like more information.",
48
+ buildingId: 3660,
49
+ buildingSlug: "test-building",
50
+ orgSlug: "test-org",
51
+ });
52
+
53
+ const submission = emailUs.onClick();
54
+
55
+ expect(requests).to.have.length(1);
56
+ expect(requests[0].url).to.equal(
57
+ "https://app.meetelise.com/platformApi/state/create/emailMe"
58
+ );
59
+ expect(JSON.parse(requests[0].requestBody ?? "{}")).to.include({
60
+ phone_number: "+447400123456",
61
+ email_address: "local.test@example.com",
62
+ });
63
+ requests[0].respond(200, { "Content-Type": "application/json" }, "{}");
64
+ await submission;
65
+
66
+ expect(window.dataLayer[window.dataLayer.length - 1]).to.include({
67
+ event: "emailUsSubmitted",
68
+ phone: "+447400123456",
69
+ });
70
+ });
71
+
72
+ it("submits the canonical international number in the Tour request", async () => {
73
+ const fakeXhr = useFakeXMLHttpRequest();
74
+ const requests: FakeRequest[] = [];
75
+ fakeXhr.onCreate = (request: FakeRequest) => requests.push(request);
76
+ const tour = document.createElement("tour-scheduler") as TourScheduler;
77
+ Object.assign(tour as unknown as TourSubmissionHarness, {
78
+ tourType: guidedTour,
79
+ selectedDate: new Date("2030-01-15T00:00:00Z"),
80
+ selectedTime: {
81
+ datetime: "2030-01-15T10:00:00",
82
+ offset: "+01:00",
83
+ },
84
+ phoneNumber: "02 1234 5678",
85
+ phoneNumberE164: "+390212345678",
86
+ email: "local.test@example.com",
87
+ });
88
+ Object.assign(tour, {
89
+ buildingId: 3660,
90
+ buildingSlug: "test-building",
91
+ orgSlug: "test-org",
92
+ firstNameInputValue: "Local",
93
+ lastNameInputValue: "Test",
94
+ });
95
+
96
+ const submission = tour.submit();
97
+
98
+ expect(requests).to.have.length(1);
99
+ expect(requests[0].url).to.equal(
100
+ "https://app.meetelise.com/platformApi/state/create/v2/scheduleMe"
101
+ );
102
+ expect(JSON.parse(requests[0].requestBody ?? "{}")).to.include({
103
+ phone_number: "+390212345678",
104
+ email_address: "local.test@example.com",
105
+ });
106
+ requests[0].respond(200, { "Content-Type": "application/json" }, "{}");
107
+ await submission;
108
+
109
+ expect(window.dataLayer[window.dataLayer.length - 1]).to.include({
110
+ event: "scheduleTourSubmitted",
111
+ phone: "+390212345678",
112
+ });
113
+ });
114
+
115
+ it("does not submit either form without a canonical phone number", async () => {
116
+ const fakeXhr = useFakeXMLHttpRequest();
117
+ const requests: FakeRequest[] = [];
118
+ fakeXhr.onCreate = (request: FakeRequest) => requests.push(request);
119
+ const emailUs = document.createElement("email-us-window") as EmailUsWindow;
120
+ Object.assign(emailUs, {
121
+ firstName: "Local",
122
+ lastName: "Test",
123
+ email: "local.test@example.com",
124
+ phoneNumber: "123",
125
+ phoneNumberE164: null,
126
+ });
127
+ await emailUs.onClick();
128
+
129
+ const tour = document.createElement("tour-scheduler") as TourScheduler;
130
+ Object.assign(tour as unknown as TourSubmissionHarness, {
131
+ tourType: guidedTour,
132
+ selectedDate: new Date("2030-01-15T00:00:00Z"),
133
+ selectedTime: {
134
+ datetime: "2030-01-15T10:00:00",
135
+ offset: "+01:00",
136
+ },
137
+ phoneNumber: "123",
138
+ phoneNumberE164: null,
139
+ email: "local.test@example.com",
140
+ });
141
+ await tour.submit();
142
+
143
+ expect(requests).to.have.length(0);
144
+ expect(emailUs.hasPhoneNumberError).to.equal(true);
145
+ });