cypress-mailisk 2.0.0 → 2.1.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 +119 -3
- package/package.json +8 -3
- package/src/mailiskCommands.d.ts +50 -0
- package/src/mailiskCommands.js +11 -1
- package/src/request.js +18 -0
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ This Cypress command does a few extra things out of the box compared to calling
|
|
|
49
49
|
|
|
50
50
|
- By default it uses the `wait` flag. This means the call won't return until at least one email is received. Disabling this flag via `wait: false` can cause it to return an empty response immediately.
|
|
51
51
|
- The request timeout is adjustable by passing `timeout` in the request options. By default it uses a timeout of 5 minutes.
|
|
52
|
-
- By default it returns emails in the last 15 minutes. This ensures that only new emails are returned.
|
|
52
|
+
- By default it returns emails in the last 15 minutes. This ensures that only new emails are returned. This can be overriden by passing the `from_timestamp` parameter (`from_timestamp: 0` will disable filtering by email age).
|
|
53
53
|
|
|
54
54
|
```js
|
|
55
55
|
// timeout of 5 minute
|
|
@@ -60,9 +60,125 @@ cy.mailiskSearchInbox(namespace, {}, { timeout: 1000 * 60 });
|
|
|
60
60
|
cy.mailiskSearchInbox(namespace, { wait: false });
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
For the full list of filters and their description see the [Search Inbox](/api-reference/search-inbox#request-1) endpoint reference.
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
### cy.mailiskGetAttachment
|
|
66
|
+
|
|
67
|
+
This command retrieves attachment metadata including download URL, filename, content type, and size.
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
cy.mailiskGetAttachment('yournamespace', 'attachment-id').then((attachment) => {
|
|
71
|
+
console.log(attachment.data.filename);
|
|
72
|
+
console.log(attachment.data.content_type);
|
|
73
|
+
console.log(attachment.data.size);
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### cy.mailiskDownloadAttachment
|
|
78
|
+
|
|
79
|
+
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.
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
cy.mailiskDownloadAttachment('yournamespace', 'attachment-id').then((buffer) => {
|
|
83
|
+
// Save attachment to file
|
|
84
|
+
cy.writeFile('downloads/attachment.pdf', buffer);
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Both commands accept optional request options as a third parameter:
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
cy.mailiskGetAttachment('yournamespace', 'attachment-id', { timeout: 30000 });
|
|
92
|
+
cy.mailiskDownloadAttachment('yournamespace', 'attachment-id', { timeout: 60000 });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Filter by TO address
|
|
96
|
+
|
|
97
|
+
The `to_addr_prefix` option allows filtering by the email's TO address. Specifically the TO address has to start with this.
|
|
98
|
+
|
|
99
|
+
For example, if someone sends an email to `my-user-1@yournamespace.mailisk.net`, you can filter it by using `my-user-1@`:
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
cy.mailiskSearchInbox(namespace, {
|
|
103
|
+
to_addr_prefix: 'my-user-1@',
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Filter by FROM address
|
|
108
|
+
|
|
109
|
+
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_.
|
|
110
|
+
|
|
111
|
+
For example, if someone sends an email from the `example.com` domain we could filter like so:
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
cy.mailiskSearchInbox(namespace, {
|
|
115
|
+
from_addr_includes: '@example.com',
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If we know a specific email address we want to listen to we can do this:
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
cy.mailiskSearchInbox(namespace, {
|
|
123
|
+
from_addr_includes: 'no-reply@example.com',
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Filter by Subject
|
|
128
|
+
|
|
129
|
+
The `subject_includes` option allows filtering by the email's Subject. Specifically the Subject has to include this (case-insensitive).
|
|
130
|
+
|
|
131
|
+
If we're testing password reset that sends an email with the subject `Password reset request`. We could filter by something like this:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
cy.mailiskSearchInbox(namespace, {
|
|
135
|
+
subject_includes: 'password reset request',
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Common test cases
|
|
140
|
+
|
|
141
|
+
### Working with email attachments
|
|
142
|
+
|
|
143
|
+
This example demonstrates how to search for emails with attachments and download them:
|
|
144
|
+
|
|
145
|
+
```js
|
|
146
|
+
describe('Test email attachments', () => {
|
|
147
|
+
const namespace = 'yournamespace';
|
|
148
|
+
const testEmailAddr = `test.user@${namespace}.mailisk.net`;
|
|
149
|
+
|
|
150
|
+
it('Finds email with attachment and downloads it', () => {
|
|
151
|
+
cy.mailiskSearchInbox(namespace, {
|
|
152
|
+
to_addr_prefix: testEmailAddr,
|
|
153
|
+
subject_includes: 'invoice',
|
|
154
|
+
}).then((response) => {
|
|
155
|
+
expect(response.data).to.not.be.empty;
|
|
156
|
+
const email = response.data[0];
|
|
157
|
+
|
|
158
|
+
// Check if email has attachments
|
|
159
|
+
expect(email.attachments).to.not.be.empty;
|
|
160
|
+
const attachment = email.attachments[0];
|
|
161
|
+
|
|
162
|
+
// Get attachment metadata
|
|
163
|
+
cy.mailiskGetAttachment(attachment.id).then((attachmentData) => {
|
|
164
|
+
expect(attachmentData.data.filename).to.contain('.pdf');
|
|
165
|
+
expect(attachmentData.data.content_type).to.equal('application/pdf');
|
|
166
|
+
|
|
167
|
+
// Download the attachment
|
|
168
|
+
cy.mailiskDownloadAttachment(attachment.id).then((buffer) => {
|
|
169
|
+
// Save to downloads folder
|
|
170
|
+
cy.writeFile(`downloads/${attachmentData.data.filename}`, buffer);
|
|
171
|
+
|
|
172
|
+
// Verify file was downloaded
|
|
173
|
+
cy.readFile(`downloads/${attachmentData.data.filename}`).should('exist');
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Password reset page
|
|
66
182
|
|
|
67
183
|
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.
|
|
68
184
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cypress-mailisk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.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,8 @@ export interface Email {
|
|
|
32
43
|
expires_timestamp: number;
|
|
33
44
|
/** The spam score as reported by SpamAssassin */
|
|
34
45
|
spam_score?: number;
|
|
46
|
+
/** The attachments of the email */
|
|
47
|
+
attachments?: EmailAttachment[];
|
|
35
48
|
}
|
|
36
49
|
|
|
37
50
|
export interface SearchInboxParams {
|
|
@@ -92,6 +105,17 @@ export interface SearchInboxResponse {
|
|
|
92
105
|
data: Email[];
|
|
93
106
|
}
|
|
94
107
|
|
|
108
|
+
export interface GetAttachmentResponse {
|
|
109
|
+
data: {
|
|
110
|
+
id: string;
|
|
111
|
+
filename: string;
|
|
112
|
+
content_type: string;
|
|
113
|
+
size: number;
|
|
114
|
+
expires_at: string | null;
|
|
115
|
+
download_url: string;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
95
119
|
declare global {
|
|
96
120
|
namespace Cypress {
|
|
97
121
|
interface Chainable {
|
|
@@ -111,6 +135,32 @@ declare global {
|
|
|
111
135
|
*/
|
|
112
136
|
options?: Partial<Cypress.RequestOptions>,
|
|
113
137
|
): Cypress.Chainable<SearchInboxResponse>;
|
|
138
|
+
|
|
139
|
+
mailiskGetAttachment(
|
|
140
|
+
/**
|
|
141
|
+
* The attachment ID to retrieve.
|
|
142
|
+
*/
|
|
143
|
+
attachmentId: string,
|
|
144
|
+
/**
|
|
145
|
+
* Request options.
|
|
146
|
+
*
|
|
147
|
+
* See https://docs.cypress.io/api/commands/request#Arguments
|
|
148
|
+
*/
|
|
149
|
+
options?: Partial<Cypress.RequestOptions>,
|
|
150
|
+
): Cypress.Chainable<GetAttachmentResponse>;
|
|
151
|
+
|
|
152
|
+
mailiskDownloadAttachment(
|
|
153
|
+
/**
|
|
154
|
+
* The attachment ID to download.
|
|
155
|
+
*/
|
|
156
|
+
attachmentId: string,
|
|
157
|
+
/**
|
|
158
|
+
* Request options.
|
|
159
|
+
*
|
|
160
|
+
* See https://docs.cypress.io/api/commands/request#Arguments
|
|
161
|
+
*/
|
|
162
|
+
options?: Partial<Cypress.RequestOptions>,
|
|
163
|
+
): Cypress.Chainable<Buffer>;
|
|
114
164
|
}
|
|
115
165
|
}
|
|
116
166
|
}
|
package/src/mailiskCommands.js
CHANGED
|
@@ -2,7 +2,7 @@ const Request = require('./request');
|
|
|
2
2
|
|
|
3
3
|
class MailiskCommands {
|
|
4
4
|
static get cypressCommands() {
|
|
5
|
-
return ['mailiskSetApiKey', 'mailiskListNamespaces', 'mailiskSearchInbox'];
|
|
5
|
+
return ['mailiskSetApiKey', 'mailiskListNamespaces', 'mailiskSearchInbox', 'mailiskGetAttachment', 'mailiskDownloadAttachment'];
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
constructor() {
|
|
@@ -66,6 +66,16 @@ class MailiskCommands {
|
|
|
66
66
|
return this.request.get(`api/emails/${namespace}/inbox?${urlParams.toString()}`, _options);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
|
|
70
|
+
mailiskGetAttachment(attachmentId, options = {}) {
|
|
71
|
+
return this.request.get(`api/attachments/${attachmentId}`, options);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
mailiskDownloadAttachment(attachmentId, options = {}) {
|
|
75
|
+
return this.mailiskGetAttachment(attachmentId, options).then((attachment) => {
|
|
76
|
+
return this.request.getBinary(attachment.data.download_url, options);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
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;
|