cypress-mailisk 2.0.1 → 2.2.1
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.
- package/README.md +174 -32
- package/package.json +8 -3
- package/src/mailiskCommands.d.ts +181 -0
- package/src/mailiskCommands.js +90 -12
- package/src/request.js +18 -0
package/README.md
CHANGED
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
# cypress-mailisk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Mailisk is an end-to-end email and SMS testing platform. It allows you to receive emails and SMS messages with code to automate tests.
|
|
4
|
+
|
|
5
|
+
- Get a unique subdomain and unlimited email addresses for free.
|
|
6
|
+
- Easily automate E2E password reset and account verification by catching emails.
|
|
7
|
+
- Receive SMS messages and automate SMS tests.
|
|
8
|
+
- Virtual SMTP and SMS support to test without 3rd party clients.
|
|
9
|
+
|
|
10
|
+
## Get started
|
|
11
|
+
|
|
12
|
+
For a more step-by-step walkthrough see the [Cypress Guide](https://docs.mailisk.com/guides/cypress.html).
|
|
13
|
+
|
|
14
|
+
### Installation
|
|
15
|
+
|
|
16
|
+
#### Install with npm
|
|
4
17
|
|
|
5
18
|
```shell
|
|
6
19
|
npm install --save-dev cypress-mailisk
|
|
7
20
|
```
|
|
8
21
|
|
|
9
|
-
|
|
22
|
+
#### Install with Yarn
|
|
10
23
|
|
|
11
24
|
```shell
|
|
12
25
|
yarn add cypress-mailisk --dev
|
|
13
26
|
```
|
|
14
27
|
|
|
28
|
+
#### Add to Cypress
|
|
29
|
+
|
|
15
30
|
After installing the package add the following in your project's `cypress/support/e2e.js`:
|
|
16
31
|
|
|
17
32
|
```js
|
|
@@ -36,78 +51,205 @@ The cypress-mailisk plugin provides additional commands which can be accessed on
|
|
|
36
51
|
|
|
37
52
|
### cy.mailiskSearchInbox
|
|
38
53
|
|
|
39
|
-
This is the main command to interact with Mailisk, it wraps the [Search Inbox](/api-reference/search-inbox) endpoint.
|
|
54
|
+
This is the main command to interact with Mailisk, it wraps the [Search Inbox](/api-reference/search-inbox) endpoint. See the reference documentation for the full list of filters and their description.
|
|
40
55
|
|
|
41
56
|
```js
|
|
42
|
-
cy.mailiskSearchInbox('yournamespace', { to_addr_prefix: 'test.user@' }).then(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
cy.mailiskSearchInbox('yournamespace', { to_addr_prefix: 'test.user@', subject_includes: 'register' }).then(
|
|
58
|
+
(response) => {
|
|
59
|
+
const emails = response.data;
|
|
60
|
+
expect(emails).to.not.be.empty;
|
|
61
|
+
},
|
|
62
|
+
);
|
|
46
63
|
```
|
|
47
64
|
|
|
48
|
-
This
|
|
65
|
+
This command does a few extra things out of the box:
|
|
49
66
|
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
67
|
+
- Waits until at least one new email arrives (override with `wait: false`).
|
|
68
|
+
- Times out after 5 minutes if nothing shows up (adjust via `requestOptions.timeout`).
|
|
69
|
+
- Ignores messages older than 15 minutes to avoid picking up leftovers from previous tests (change via `from_timestamp`).
|
|
70
|
+
|
|
71
|
+
#### Quick examples
|
|
53
72
|
|
|
54
73
|
```js
|
|
55
|
-
//
|
|
74
|
+
// wait up to the default 5 min for *any* new mail
|
|
56
75
|
cy.mailiskSearchInbox(namespace);
|
|
57
|
-
//
|
|
76
|
+
// custom 60-second timeout
|
|
58
77
|
cy.mailiskSearchInbox(namespace, {}, { timeout: 1000 * 60 });
|
|
59
|
-
//
|
|
78
|
+
// polling pattern — return immediately, even if inbox is empty
|
|
60
79
|
cy.mailiskSearchInbox(namespace, { wait: false });
|
|
80
|
+
// returns the last 20 emails in the namespace immediately
|
|
81
|
+
cy.mailiskSearchInbox(namespace, { wait: false, from_timestamp: 0, limit: 20 });
|
|
61
82
|
```
|
|
62
83
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
### Filter by TO address
|
|
66
|
-
|
|
67
|
-
The `to_addr_prefix` option allows filtering by the email's TO address. Specifically the TO address has to start with this.
|
|
84
|
+
#### Filter by destination address
|
|
68
85
|
|
|
69
|
-
|
|
86
|
+
A common pattern is to wait for the email your UI just triggered (e.g. password-reset).
|
|
87
|
+
Pass `to_addr_prefix` so you don’t pick up stale messages:
|
|
70
88
|
|
|
71
89
|
```js
|
|
72
90
|
cy.mailiskSearchInbox(namespace, {
|
|
73
|
-
to_addr_prefix:
|
|
91
|
+
to_addr_prefix: `test.user@${namespace}.mailisk.net`,
|
|
92
|
+
}).then((response) => {
|
|
93
|
+
const emails = response.data;
|
|
94
|
+
expect(emails).to.not.be.empty;
|
|
74
95
|
});
|
|
75
96
|
```
|
|
76
97
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
The `from_addr_includes` option allows filtering by the email's FROM address. Specifically the TO address has to include this. Note that this is different from the to address as it is _includes_ not _prefix_.
|
|
98
|
+
#### Filter by sender address
|
|
80
99
|
|
|
81
|
-
|
|
100
|
+
Use `from_addr_includes` to narrow results to a sender or domain. This is useful when multiple systems write to the same namespace but only one sender matters for the test.
|
|
82
101
|
|
|
83
102
|
```js
|
|
84
103
|
cy.mailiskSearchInbox(namespace, {
|
|
85
104
|
from_addr_includes: '@example.com',
|
|
105
|
+
}).then((response) => {
|
|
106
|
+
const emails = response.data;
|
|
107
|
+
expect(emails).to.not.be.empty;
|
|
86
108
|
});
|
|
87
109
|
```
|
|
88
110
|
|
|
89
|
-
|
|
111
|
+
#### Filter by subject contents
|
|
112
|
+
|
|
113
|
+
The `subject_includes` filter helps when the UI sends different notification types from the same sender. Matching is case-insensitive and only requires the provided string to be present.
|
|
90
114
|
|
|
91
115
|
```js
|
|
92
116
|
cy.mailiskSearchInbox(namespace, {
|
|
93
|
-
|
|
117
|
+
to_addr_prefix: `test.user@${namespace}.mailisk.net`,
|
|
118
|
+
subject_includes: 'password reset',
|
|
119
|
+
}).then((response) => {
|
|
120
|
+
const emails = response.data;
|
|
121
|
+
expect(emails).to.not.be.empty;
|
|
94
122
|
});
|
|
95
123
|
```
|
|
96
124
|
|
|
97
|
-
###
|
|
125
|
+
### cy.mailiskGetAttachment
|
|
98
126
|
|
|
99
|
-
|
|
127
|
+
This command retrieves attachment metadata including download URL, filename, content type, and size.
|
|
100
128
|
|
|
101
|
-
|
|
129
|
+
```js
|
|
130
|
+
cy.mailiskGetAttachment('attachment-id').then((attachment) => {
|
|
131
|
+
console.log(attachment.data.filename);
|
|
132
|
+
console.log(attachment.data.content_type);
|
|
133
|
+
console.log(attachment.data.size);
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### cy.mailiskDownloadAttachment
|
|
138
|
+
|
|
139
|
+
This command downloads the actual attachment content as a Buffer. It first retrieves the attachment metadata, then downloads the file from the provided download URL.
|
|
102
140
|
|
|
103
141
|
```js
|
|
104
|
-
cy.
|
|
105
|
-
|
|
142
|
+
cy.mailiskDownloadAttachment('attachment-id').then((buffer) => {
|
|
143
|
+
cy.writeFile('downloads/attachment.pdf', buffer);
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### cy.mailiskSearchSms
|
|
148
|
+
|
|
149
|
+
This is the main command to interact with Mailisk SMS, it wraps the [Search SMS](/api-reference/search-sms) endpoint. Use a phone number that is registered to your account.
|
|
150
|
+
|
|
151
|
+
```js
|
|
152
|
+
cy.mailiskSearchSms('phoneNumber', { from_date: new Date('2023-01-01T00:00:00Z'), limit: 5 }).then((response) => {
|
|
153
|
+
const smsMessages = response.data;
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This Cypress command does a few extra things out of the box compared to calling the raw API directly:
|
|
158
|
+
|
|
159
|
+
- Waits until at least one SMS matches the filters (override with `wait: false`).
|
|
160
|
+
- Times out after 5 minutes if nothing shows up (adjust via `requestOptions.timeout`).
|
|
161
|
+
- Ignores SMS older than 15 minutes by default (override with `from_date`).
|
|
162
|
+
|
|
163
|
+
#### Quick examples
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
// wait up to the default 5 min for *any* new SMS sent to the phone number
|
|
167
|
+
cy.mailiskSearchSms('phoneNumber');
|
|
168
|
+
// custom 60-second timeout
|
|
169
|
+
cy.mailiskSearchSms('phoneNumber', {}, { timeout: 1000 * 60 });
|
|
170
|
+
// polling pattern — return immediately, even if inbox is empty
|
|
171
|
+
cy.mailiskSearchSms('phoneNumber', { wait: false });
|
|
172
|
+
// returns the last 20 SMS messages for the phone number immediately
|
|
173
|
+
cy.mailiskSearchSms('phoneNumber', { wait: false, from_date: new Date(0), limit: 20 });
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### Filter by sender phone number
|
|
177
|
+
|
|
178
|
+
Use `from_number` to narrow results to a specific phone number.
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
cy.mailiskSearchSms('phoneNumber', {
|
|
182
|
+
from_number: '1234567890',
|
|
183
|
+
}).then((response) => {
|
|
184
|
+
const smsMessages = response.data;
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### Filter by body contents
|
|
189
|
+
|
|
190
|
+
Use `body` to narrow results to a specific message body.
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
cy.mailiskSearchSms('phoneNumber', {
|
|
194
|
+
body: 'Here is your code:',
|
|
195
|
+
}).then((response) => {
|
|
196
|
+
const smsMessages = response.data;
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### cy.mailiskListSmsNumbers
|
|
201
|
+
|
|
202
|
+
This command lists the SMS numbers available to the current API key.
|
|
203
|
+
|
|
204
|
+
```js
|
|
205
|
+
cy.mailiskListSmsNumbers().then((response) => {
|
|
206
|
+
const smsNumbers = response.data;
|
|
207
|
+
expect(smsNumbers).to.not.be.empty;
|
|
106
208
|
});
|
|
107
209
|
```
|
|
108
210
|
|
|
109
211
|
## Common test cases
|
|
110
212
|
|
|
213
|
+
### Working with email attachments
|
|
214
|
+
|
|
215
|
+
This example demonstrates how to search for emails with attachments and download them:
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
describe('Test email attachments', () => {
|
|
219
|
+
const namespace = 'yournamespace';
|
|
220
|
+
const testEmailAddr = `test.user@${namespace}.mailisk.net`;
|
|
221
|
+
|
|
222
|
+
it('Finds email with attachment and downloads it', () => {
|
|
223
|
+
cy.mailiskSearchInbox(namespace, {
|
|
224
|
+
to_addr_prefix: testEmailAddr,
|
|
225
|
+
subject_includes: 'invoice',
|
|
226
|
+
}).then((response) => {
|
|
227
|
+
expect(response.data).to.not.be.empty;
|
|
228
|
+
const email = response.data[0];
|
|
229
|
+
|
|
230
|
+
// Check if email has attachments
|
|
231
|
+
expect(email.attachments).to.not.be.empty;
|
|
232
|
+
const attachment = email.attachments[0];
|
|
233
|
+
|
|
234
|
+
// Get attachment metadata
|
|
235
|
+
cy.mailiskGetAttachment(attachment.id).then((attachmentData) => {
|
|
236
|
+
expect(attachmentData.data.filename).to.contain('.pdf');
|
|
237
|
+
expect(attachmentData.data.content_type).to.equal('application/pdf');
|
|
238
|
+
|
|
239
|
+
// Download the attachment
|
|
240
|
+
cy.mailiskDownloadAttachment(attachment.id).then((buffer) => {
|
|
241
|
+
// Save to downloads folder
|
|
242
|
+
cy.writeFile(`downloads/${attachmentData.data.filename}`, buffer);
|
|
243
|
+
|
|
244
|
+
// Verify file was downloaded
|
|
245
|
+
cy.readFile(`downloads/${attachmentData.data.filename}`).should('exist');
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
111
253
|
### Password reset page
|
|
112
254
|
|
|
113
255
|
This example demonstrates going to a password reset page, requesting a new password, receiving reset code link via email and finally setting the new password.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cypress-mailisk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Mailisk library for Cypress",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mailisk",
|
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
"main": "index.js",
|
|
14
14
|
"types": "src/mailiskCommands.d.ts",
|
|
15
15
|
"scripts": {
|
|
16
|
-
"tsc": "node_modules/.bin/tsc src/mailiskCommands.d.ts --types node"
|
|
16
|
+
"tsc": "node_modules/.bin/tsc src/mailiskCommands.d.ts --types node",
|
|
17
|
+
"test": "jest",
|
|
18
|
+
"test:watch": "jest --watch",
|
|
19
|
+
"test:coverage": "jest --coverage"
|
|
17
20
|
},
|
|
18
21
|
"peerDependencies": {
|
|
19
22
|
"cypress": ">= 2.1.0"
|
|
@@ -32,6 +35,8 @@
|
|
|
32
35
|
},
|
|
33
36
|
"homepage": "https://github.com/mailisk-app/cypress-mailisk#readme",
|
|
34
37
|
"devDependencies": {
|
|
35
|
-
"typescript": "^4.7.4"
|
|
38
|
+
"typescript": "^4.7.4",
|
|
39
|
+
"jest": "^29.0.0",
|
|
40
|
+
"@jest/globals": "^29.0.0"
|
|
36
41
|
}
|
|
37
42
|
}
|
package/src/mailiskCommands.d.ts
CHANGED
|
@@ -7,6 +7,17 @@ export interface EmailAddress {
|
|
|
7
7
|
name?: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
export interface EmailAttachment {
|
|
11
|
+
/** Unique identifier for the attachment */
|
|
12
|
+
id: string;
|
|
13
|
+
/** Filename of the attachment */
|
|
14
|
+
filename: string;
|
|
15
|
+
/** Content type of the attachment */
|
|
16
|
+
content_type: string;
|
|
17
|
+
/** Size in bytes of the attachment */
|
|
18
|
+
size: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
10
21
|
export interface Email {
|
|
11
22
|
/** Namespace scoped ID */
|
|
12
23
|
id: string;
|
|
@@ -32,6 +43,46 @@ export interface Email {
|
|
|
32
43
|
expires_timestamp: number;
|
|
33
44
|
/** The spam score as reported by SpamAssassin */
|
|
34
45
|
spam_score?: number;
|
|
46
|
+
/** The headers of the email */
|
|
47
|
+
headers?: Record<string, string>;
|
|
48
|
+
/** The attachments of the email */
|
|
49
|
+
attachments?: EmailAttachment[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface SmsMessage {
|
|
53
|
+
/** Unique identifier for the message */
|
|
54
|
+
id: string;
|
|
55
|
+
/** Unique identifier for the SMS phone number */
|
|
56
|
+
sms_phone_number_id: string;
|
|
57
|
+
/** Body of the message */
|
|
58
|
+
body: string;
|
|
59
|
+
/** From number of the message */
|
|
60
|
+
from_number: string;
|
|
61
|
+
/** To number of the message */
|
|
62
|
+
to_number: string;
|
|
63
|
+
/** Provider message ID */
|
|
64
|
+
provider_message_id?: string;
|
|
65
|
+
/** Date and time the message was created */
|
|
66
|
+
created_at: string;
|
|
67
|
+
/** Direction of the message */
|
|
68
|
+
direction: 'inbound' | 'outbound';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface SmsNumber {
|
|
72
|
+
/** Unique identifier for the SMS number */
|
|
73
|
+
id: string;
|
|
74
|
+
/** Unique identifier for the organisation */
|
|
75
|
+
organisation_id: string;
|
|
76
|
+
/** Status of the SMS number */
|
|
77
|
+
status: 'requested' | 'active' | 'disabled';
|
|
78
|
+
/** Country of the SMS number */
|
|
79
|
+
country: string;
|
|
80
|
+
/** SMS Phone number */
|
|
81
|
+
phone_number?: string;
|
|
82
|
+
/** Date and time the SMS number was created */
|
|
83
|
+
created_at: string;
|
|
84
|
+
/** Date and time the SMS number was updated */
|
|
85
|
+
updated_at: string;
|
|
35
86
|
}
|
|
36
87
|
|
|
37
88
|
export interface SearchInboxParams {
|
|
@@ -92,9 +143,87 @@ export interface SearchInboxResponse {
|
|
|
92
143
|
data: Email[];
|
|
93
144
|
}
|
|
94
145
|
|
|
146
|
+
export interface SmtpSettings {
|
|
147
|
+
data: {
|
|
148
|
+
host: string;
|
|
149
|
+
port: number;
|
|
150
|
+
username: string;
|
|
151
|
+
password: string;
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface GetAttachmentResponse {
|
|
156
|
+
data: {
|
|
157
|
+
id: string;
|
|
158
|
+
filename: string;
|
|
159
|
+
content_type: string;
|
|
160
|
+
size: number;
|
|
161
|
+
expires_at: string | null;
|
|
162
|
+
download_url: string;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface ListNamespacesResponse {
|
|
167
|
+
total_count: number;
|
|
168
|
+
data: { id: string; namespace: string }[];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface SearchSmsMessagesParams {
|
|
172
|
+
/**
|
|
173
|
+
* The maximum number of SMS messages returned (1-100), used alongside `offset` for pagination.
|
|
174
|
+
*/
|
|
175
|
+
limit?: number;
|
|
176
|
+
/**
|
|
177
|
+
* The number of SMS messages to skip/ignore, used alongside `limit` for pagination.
|
|
178
|
+
*/
|
|
179
|
+
offset?: number;
|
|
180
|
+
/**
|
|
181
|
+
* Filter messages by body contents (case insensitive).
|
|
182
|
+
*/
|
|
183
|
+
body?: string;
|
|
184
|
+
/**
|
|
185
|
+
* Filter messages by sender phone number prefix.
|
|
186
|
+
*/
|
|
187
|
+
from_number?: string;
|
|
188
|
+
/**
|
|
189
|
+
* Filter messages created on or after this date (Date object or ISO 8601 string).
|
|
190
|
+
*/
|
|
191
|
+
from_date?: Date | string;
|
|
192
|
+
/**
|
|
193
|
+
* Filter messages created on or before this date (Date object or ISO 8601 string).
|
|
194
|
+
*/
|
|
195
|
+
to_date?: Date | string;
|
|
196
|
+
/**
|
|
197
|
+
* When true, keep the request open until at least one SMS is returned.
|
|
198
|
+
*/
|
|
199
|
+
wait?: boolean;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface SearchSmsMessagesResponse {
|
|
203
|
+
total_count: number;
|
|
204
|
+
options: SearchSmsMessagesParams;
|
|
205
|
+
data: SmsMessage[];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface ListSmsNumbersResponse {
|
|
209
|
+
total_count: number;
|
|
210
|
+
data: SmsNumber[];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface SendVirtualSmsParams {
|
|
214
|
+
/** The phone number to send the SMS from */
|
|
215
|
+
from_number: string;
|
|
216
|
+
/** The phone number to send the SMS to */
|
|
217
|
+
to_number: string;
|
|
218
|
+
/** The body of the SMS message */
|
|
219
|
+
body: string;
|
|
220
|
+
}
|
|
221
|
+
|
|
95
222
|
declare global {
|
|
96
223
|
namespace Cypress {
|
|
97
224
|
interface Chainable {
|
|
225
|
+
mailiskListNamespaces(): Cypress.Chainable<ListNamespacesResponse>;
|
|
226
|
+
|
|
98
227
|
mailiskSearchInbox(
|
|
99
228
|
/**
|
|
100
229
|
* The unique namespace to search.
|
|
@@ -111,6 +240,58 @@ declare global {
|
|
|
111
240
|
*/
|
|
112
241
|
options?: Partial<Cypress.RequestOptions>,
|
|
113
242
|
): Cypress.Chainable<SearchInboxResponse>;
|
|
243
|
+
|
|
244
|
+
mailiskGetAttachment(
|
|
245
|
+
/**
|
|
246
|
+
* The attachment ID to retrieve.
|
|
247
|
+
*/
|
|
248
|
+
attachmentId: string,
|
|
249
|
+
/**
|
|
250
|
+
* Request options.
|
|
251
|
+
*
|
|
252
|
+
* See https://docs.cypress.io/api/commands/request#Arguments
|
|
253
|
+
*/
|
|
254
|
+
options?: Partial<Cypress.RequestOptions>,
|
|
255
|
+
): Cypress.Chainable<GetAttachmentResponse>;
|
|
256
|
+
|
|
257
|
+
mailiskDownloadAttachment(
|
|
258
|
+
/**
|
|
259
|
+
* The attachment ID to download.
|
|
260
|
+
*/
|
|
261
|
+
attachmentId: string,
|
|
262
|
+
/**
|
|
263
|
+
* Request options.
|
|
264
|
+
*
|
|
265
|
+
* See https://docs.cypress.io/api/commands/request#Arguments
|
|
266
|
+
*/
|
|
267
|
+
options?: Partial<Cypress.RequestOptions>,
|
|
268
|
+
): Cypress.Chainable<Buffer>;
|
|
269
|
+
|
|
270
|
+
mailiskSearchSms(
|
|
271
|
+
/**
|
|
272
|
+
* The phone number to search.
|
|
273
|
+
*/
|
|
274
|
+
phoneNumber: string,
|
|
275
|
+
/**
|
|
276
|
+
* Search parameters.
|
|
277
|
+
*/
|
|
278
|
+
params?: SearchSmsMessagesParams,
|
|
279
|
+
/**
|
|
280
|
+
* Request options.
|
|
281
|
+
*
|
|
282
|
+
* See https://docs.cypress.io/api/commands/request#Arguments
|
|
283
|
+
*/
|
|
284
|
+
options?: Partial<Cypress.RequestOptions>,
|
|
285
|
+
): Cypress.Chainable<SearchSmsMessagesResponse>;
|
|
286
|
+
|
|
287
|
+
mailiskListSmsNumbers(
|
|
288
|
+
/**
|
|
289
|
+
* Request options.
|
|
290
|
+
*
|
|
291
|
+
* See https://docs.cypress.io/api/commands/request#Arguments
|
|
292
|
+
*/
|
|
293
|
+
options?: Partial<Cypress.RequestOptions>,
|
|
294
|
+
): Cypress.Chainable<ListSmsNumbersResponse>;
|
|
114
295
|
}
|
|
115
296
|
}
|
|
116
297
|
}
|
package/src/mailiskCommands.js
CHANGED
|
@@ -2,23 +2,31 @@ const Request = require('./request');
|
|
|
2
2
|
|
|
3
3
|
class MailiskCommands {
|
|
4
4
|
static get cypressCommands() {
|
|
5
|
-
return [
|
|
5
|
+
return [
|
|
6
|
+
'mailiskSetApiKey',
|
|
7
|
+
'mailiskListNamespaces',
|
|
8
|
+
'mailiskSearchInbox',
|
|
9
|
+
'mailiskGetAttachment',
|
|
10
|
+
'mailiskDownloadAttachment',
|
|
11
|
+
'mailiskSearchSms',
|
|
12
|
+
'mailiskListSmsNumbers',
|
|
13
|
+
];
|
|
6
14
|
}
|
|
7
15
|
|
|
8
16
|
constructor() {
|
|
9
|
-
const
|
|
10
|
-
this.mailiskSetApiKey(
|
|
17
|
+
const apiKey = Cypress.env('MAILISK_API_KEY');
|
|
18
|
+
this.mailiskSetApiKey(apiKey);
|
|
11
19
|
}
|
|
12
20
|
|
|
13
21
|
mailiskSetApiKey(apiKey) {
|
|
14
|
-
this.request = new Request({ apiKey,
|
|
22
|
+
this.request = new Request({ apiKey, apiUrl: Cypress.env('MAILISK_API_URL') });
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
mailiskListNamespaces() {
|
|
18
26
|
return this.request.get('api/namespaces');
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
_mailiskSearchInboxAction(namespace, _options, urlParams, startTime, nextTimeout) {
|
|
22
30
|
return this.request
|
|
23
31
|
.get(`api/emails/${namespace}/inbox?${urlParams.toString()}`, { ..._options, timeout: nextTimeout })
|
|
24
32
|
.then((response) => {
|
|
@@ -27,27 +35,27 @@ class MailiskCommands {
|
|
|
27
35
|
}
|
|
28
36
|
const timeout = Math.max(_options.timeout - (Date.now() - startTime), 1);
|
|
29
37
|
cy.wait(Math.min(timeout, 9000), { log: false });
|
|
30
|
-
return this.
|
|
38
|
+
return this._mailiskSearchInboxAction(namespace, _options, urlParams, startTime, timeout);
|
|
31
39
|
});
|
|
32
40
|
}
|
|
33
41
|
|
|
34
|
-
mailiskSearchInbox(namespace, params, options = {}) {
|
|
42
|
+
mailiskSearchInbox(namespace, params = {}, options = {}) {
|
|
35
43
|
let _params = { ...params };
|
|
36
44
|
|
|
37
45
|
// default from_timestamp, 15 minutes before starting this request
|
|
38
|
-
if (
|
|
39
|
-
_params.from_timestamp = Math.floor(
|
|
46
|
+
if (_params.from_timestamp == null) {
|
|
47
|
+
_params.from_timestamp = Math.floor(Date.now() / 1000) - 15 * 60;
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
// by default wait for email
|
|
43
|
-
if (
|
|
51
|
+
if (_params.wait !== false) {
|
|
44
52
|
_params.wait = true;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
const urlParams = new URLSearchParams();
|
|
48
56
|
for (const key in _params) {
|
|
49
57
|
const value = _params[key];
|
|
50
|
-
if (value) urlParams.set(key, value.toString());
|
|
58
|
+
if (value !== undefined && value !== null) urlParams.set(key, value.toString());
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
let _options = { ...options };
|
|
@@ -61,11 +69,81 @@ class MailiskCommands {
|
|
|
61
69
|
if (_params.wait) {
|
|
62
70
|
urlParams.delete('wait');
|
|
63
71
|
const startTime = Date.now();
|
|
64
|
-
return this.
|
|
72
|
+
return this._mailiskSearchInboxAction(namespace, _options, urlParams, startTime, _options.timeout);
|
|
65
73
|
} else {
|
|
66
74
|
return this.request.get(`api/emails/${namespace}/inbox?${urlParams.toString()}`, _options);
|
|
67
75
|
}
|
|
68
76
|
}
|
|
77
|
+
|
|
78
|
+
mailiskGetAttachment(attachmentId, options = {}) {
|
|
79
|
+
return this.request.get(`api/attachments/${attachmentId}`, options);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
mailiskDownloadAttachment(attachmentId, options = {}) {
|
|
83
|
+
return this.mailiskGetAttachment(attachmentId, options).then((attachment) => {
|
|
84
|
+
return this.request.getBinary(attachment.data.download_url, options);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
_mailiskSearchSmsAction(phoneNumber, _options, urlParams, startTime, nextTimeout) {
|
|
89
|
+
return this.request
|
|
90
|
+
.get(`api/sms/${phoneNumber}/messages?${urlParams.toString()}`, { ..._options, timeout: nextTimeout })
|
|
91
|
+
.then((response) => {
|
|
92
|
+
if (response.total_count !== 0) {
|
|
93
|
+
return response;
|
|
94
|
+
}
|
|
95
|
+
const timeout = Math.max(_options.timeout - (Date.now() - startTime), 1);
|
|
96
|
+
cy.wait(Math.min(timeout, 9000), { log: false });
|
|
97
|
+
return this._mailiskSearchSmsAction(phoneNumber, _options, urlParams, startTime, timeout);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
mailiskSearchSms(phoneNumber, params = {}, options = {}) {
|
|
102
|
+
let _params = { ...params };
|
|
103
|
+
|
|
104
|
+
// default from_date, 15 minutes before starting this request
|
|
105
|
+
if (_params.from_date == null) {
|
|
106
|
+
_params.from_date = new Date(Date.now() - 15 * 60 * 1000);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// by default wait for email
|
|
110
|
+
if (params.wait !== false) {
|
|
111
|
+
_params.wait = true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (_params.from_date instanceof Date) {
|
|
115
|
+
_params.from_date = _params.from_date.toISOString();
|
|
116
|
+
}
|
|
117
|
+
if (_params.to_date instanceof Date) {
|
|
118
|
+
_params.to_date = _params.to_date.toISOString();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const urlParams = new URLSearchParams();
|
|
122
|
+
for (const key in _params) {
|
|
123
|
+
const value = _params[key];
|
|
124
|
+
if (value !== undefined && value !== null) urlParams.set(key, value.toString());
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let _options = { ...options };
|
|
128
|
+
|
|
129
|
+
// by default wait 5 minutes for emails
|
|
130
|
+
if (_params.wait && !options.timeout) {
|
|
131
|
+
_options.timeout = 1000 * 60 * 5;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// temporary workaround due cypress not supporting overriding maxRedirects
|
|
135
|
+
if (_params.wait) {
|
|
136
|
+
urlParams.delete('wait');
|
|
137
|
+
const startTime = Date.now();
|
|
138
|
+
return this._mailiskSearchSmsAction(phoneNumber, _options, urlParams, startTime, _options.timeout);
|
|
139
|
+
} else {
|
|
140
|
+
return this.request.get(`api/sms/${phoneNumber}/messages?${urlParams.toString()}`, _options);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
mailiskListSmsNumbers(options = {}) {
|
|
145
|
+
return this.request.get(`api/sms/numbers`, options);
|
|
146
|
+
}
|
|
69
147
|
}
|
|
70
148
|
|
|
71
149
|
module.exports = MailiskCommands;
|
package/src/request.js
CHANGED
|
@@ -81,6 +81,24 @@ class Request {
|
|
|
81
81
|
del(path, opts) {
|
|
82
82
|
return this.request('DELETE', path, undefined, opts);
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
getBinary(url, opts) {
|
|
86
|
+
// For binary downloads, we need to use the full URL directly
|
|
87
|
+
const options = {
|
|
88
|
+
method: 'GET',
|
|
89
|
+
url: url,
|
|
90
|
+
encoding: null, // This tells Cypress to return binary data
|
|
91
|
+
...opts,
|
|
92
|
+
};
|
|
93
|
+
options.failOnStatusCode = false;
|
|
94
|
+
return cy.request(options).then((response) => {
|
|
95
|
+
if (response.isOkStatusCode) {
|
|
96
|
+
return Buffer.from(response.body);
|
|
97
|
+
}
|
|
98
|
+
// Use the same error handling as regular requests
|
|
99
|
+
return this.getResponseHandler()(response);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
84
102
|
}
|
|
85
103
|
|
|
86
104
|
module.exports = Request;
|