proxymail-qa 0.1.1 → 0.3.0
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 +3 -0
- package/dist/index.d.ts +41 -4
- package/dist/index.js +53 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -86,6 +86,9 @@ cy.task('createAddress').then(({ address }) => {
|
|
|
86
86
|
// A persona with a date of birth for an age band, and a country.
|
|
87
87
|
await qa.createAddress({ persona: true, age: 'under13', country: 'GB' });
|
|
88
88
|
|
|
89
|
+
// Find a test account made earlier: an under-18 in GB with a saved password.
|
|
90
|
+
const [teen] = await qa.listAddresses({ tags: ['age-gate'], country: 'GB', maxAge: 17, hasPassword: true });
|
|
91
|
+
|
|
89
92
|
// The link that opens a mobile app (myapp://…) when the email also has a web one.
|
|
90
93
|
const { value: appLink } = await qa.waitForLink(address, { app: true });
|
|
91
94
|
|
package/dist/index.d.ts
CHANGED
|
@@ -57,6 +57,16 @@ export interface CreateAddressInput {
|
|
|
57
57
|
dateOfBirth?: string;
|
|
58
58
|
country?: string;
|
|
59
59
|
}
|
|
60
|
+
export interface ListAddressesOptions {
|
|
61
|
+
limit?: number;
|
|
62
|
+
before?: string;
|
|
63
|
+
tags?: string[];
|
|
64
|
+
country?: string;
|
|
65
|
+
minAge?: number;
|
|
66
|
+
maxAge?: number;
|
|
67
|
+
hasPassword?: boolean;
|
|
68
|
+
search?: string;
|
|
69
|
+
}
|
|
60
70
|
export interface AddressPatch {
|
|
61
71
|
label?: string | null;
|
|
62
72
|
notes?: string | null;
|
|
@@ -101,6 +111,32 @@ export interface WaitOptions {
|
|
|
101
111
|
since?: Date | string;
|
|
102
112
|
}
|
|
103
113
|
export type LinkType = 'verify' | 'magic_signin' | 'invite' | 'reset' | 'any';
|
|
114
|
+
export interface EmailSummary {
|
|
115
|
+
received_at: string;
|
|
116
|
+
service: string | null;
|
|
117
|
+
service_domain: string | null;
|
|
118
|
+
type: 'code' | 'link' | null;
|
|
119
|
+
subtype: string | null;
|
|
120
|
+
email_id: string;
|
|
121
|
+
}
|
|
122
|
+
export interface EmailCount {
|
|
123
|
+
address: string;
|
|
124
|
+
since: string | null;
|
|
125
|
+
count: number;
|
|
126
|
+
emails: EmailSummary[];
|
|
127
|
+
}
|
|
128
|
+
export interface CountOptions {
|
|
129
|
+
since?: Date | string;
|
|
130
|
+
service?: string;
|
|
131
|
+
type?: 'code' | 'link';
|
|
132
|
+
subtype?: CountSubtype | CountSubtype[];
|
|
133
|
+
}
|
|
134
|
+
export type CountSubtype = 'otp' | 'coupon' | 'verify' | 'magic_signin' | 'invite' | 'reset' | 'other' | 'any';
|
|
135
|
+
export interface NoEmail {
|
|
136
|
+
address: string;
|
|
137
|
+
since: string;
|
|
138
|
+
until: string;
|
|
139
|
+
}
|
|
104
140
|
export declare class ProxyMailQAError extends Error {
|
|
105
141
|
readonly status: number;
|
|
106
142
|
readonly code: string;
|
|
@@ -120,10 +156,7 @@ export declare class ProxyMailQA {
|
|
|
120
156
|
password: true;
|
|
121
157
|
}): Promise<CreatedAddressWithPassword>;
|
|
122
158
|
createAddress(input?: CreateAddressInput): Promise<CreatedAddress>;
|
|
123
|
-
listAddresses(options?:
|
|
124
|
-
limit?: number;
|
|
125
|
-
before?: string;
|
|
126
|
-
}): Promise<Address[]>;
|
|
159
|
+
listAddresses(options?: ListAddressesOptions): Promise<Address[]>;
|
|
127
160
|
getAddress(address: string): Promise<Address>;
|
|
128
161
|
updateAddress(address: string, patch: AddressPatch): Promise<Address>;
|
|
129
162
|
deleteAddress(address: string): Promise<void>;
|
|
@@ -137,6 +170,10 @@ export declare class ProxyMailQA {
|
|
|
137
170
|
includeHtml?: boolean;
|
|
138
171
|
limit?: number;
|
|
139
172
|
}): Promise<Record<string, unknown>[]>;
|
|
173
|
+
countEmails(address: string, options?: CountOptions): Promise<EmailCount>;
|
|
174
|
+
expectNoEmail(address: string, options?: CountOptions & {
|
|
175
|
+
timeout?: number;
|
|
176
|
+
}): Promise<NoEmail>;
|
|
140
177
|
checkDelivery(address: string): Promise<DeliveryStatus>;
|
|
141
178
|
variants(address: string): Promise<Variants>;
|
|
142
179
|
setPassword(address: string, options: {
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,19 @@ export class ProxyMailQAError extends Error {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
const TIMED_OUT = /^No (code|link) arrived/;
|
|
25
|
+
function countQuery(options, extra = {}) {
|
|
26
|
+
const query = new URLSearchParams(extra);
|
|
27
|
+
if (options.since !== undefined)
|
|
28
|
+
query.set('since', new Date(options.since).toISOString());
|
|
29
|
+
if (options.service)
|
|
30
|
+
query.set('service', options.service);
|
|
31
|
+
if (options.type)
|
|
32
|
+
query.set('type', options.type);
|
|
33
|
+
const subtype = [options.subtype ?? []].flat().join(',');
|
|
34
|
+
if (subtype)
|
|
35
|
+
query.set('subtype', subtype);
|
|
36
|
+
return query.size ? `?${query}` : '';
|
|
37
|
+
}
|
|
25
38
|
const MAX_WAIT_SECONDS = 30;
|
|
26
39
|
export class ProxyMailQA {
|
|
27
40
|
apiKey;
|
|
@@ -66,12 +79,26 @@ export class ProxyMailQA {
|
|
|
66
79
|
country: input.country,
|
|
67
80
|
});
|
|
68
81
|
}
|
|
82
|
+
// Newest first. With filters, finds test accounts made earlier, such as
|
|
83
|
+
// an under-18 in GB with a saved password: every filter given must match.
|
|
69
84
|
listAddresses(options = {}) {
|
|
70
85
|
const query = new URLSearchParams();
|
|
71
86
|
if (options.limit)
|
|
72
87
|
query.set('limit', String(options.limit));
|
|
73
88
|
if (options.before)
|
|
74
89
|
query.set('before', options.before);
|
|
90
|
+
for (const tag of options.tags ?? [])
|
|
91
|
+
query.append('tag', tag);
|
|
92
|
+
if (options.country)
|
|
93
|
+
query.set('country', options.country);
|
|
94
|
+
if (options.minAge !== undefined)
|
|
95
|
+
query.set('min_age', String(options.minAge));
|
|
96
|
+
if (options.maxAge !== undefined)
|
|
97
|
+
query.set('max_age', String(options.maxAge));
|
|
98
|
+
if (options.hasPassword !== undefined)
|
|
99
|
+
query.set('has_password', String(options.hasPassword));
|
|
100
|
+
if (options.search)
|
|
101
|
+
query.set('search', options.search);
|
|
75
102
|
return this.request('GET', `/addresses${query.size ? `?${query}` : ''}`);
|
|
76
103
|
}
|
|
77
104
|
getAddress(address) {
|
|
@@ -107,6 +134,32 @@ export class ProxyMailQA {
|
|
|
107
134
|
query.set('limit', String(options.limit));
|
|
108
135
|
return this.request('GET', `/addresses/${encodeURIComponent(address)}/messages${query.size ? `?${query}` : ''}`);
|
|
109
136
|
}
|
|
137
|
+
// How many emails reached the address (since a time, from a service, with a
|
|
138
|
+
// code or link), each summarised without its content. Doesn't wait: count
|
|
139
|
+
// after the wait for the first email returns, so a duplicate has had time
|
|
140
|
+
// to arrive. Without since, every email the address has received.
|
|
141
|
+
countEmails(address, options = {}) {
|
|
142
|
+
return this.request('GET', `/addresses/${encodeURIComponent(address)}/count${countQuery(options)}`);
|
|
143
|
+
}
|
|
144
|
+
// Resolves when no matching email arrives within timeout seconds (default
|
|
145
|
+
// 30; longer repeats the request), for checks such as "an unsubscribed user
|
|
146
|
+
// gets nothing". Throws ProxyMailQAError (status 409, code email_arrived)
|
|
147
|
+
// as soon as one does. Pass since as the time of the action, so an email
|
|
148
|
+
// that came before the call still counts; without it, from now.
|
|
149
|
+
async expectNoEmail(address, options = {}) {
|
|
150
|
+
const deadline = Date.now() + (options.timeout ?? MAX_WAIT_SECONDS) * 1000;
|
|
151
|
+
let since = options.since;
|
|
152
|
+
for (;;) {
|
|
153
|
+
const left = Math.max(0, Math.min(MAX_WAIT_SECONDS, Math.ceil((deadline - Date.now()) / 1000)));
|
|
154
|
+
const query = countQuery({ ...options, since }, { timeout: String(left) });
|
|
155
|
+
const result = await this.request('GET', `/addresses/${encodeURIComponent(address)}/none${query}`);
|
|
156
|
+
// The server's since, so later requests watch from the same moment
|
|
157
|
+
// whatever this machine's clock says.
|
|
158
|
+
since = result.since;
|
|
159
|
+
if (Date.now() >= deadline - 500)
|
|
160
|
+
return { address: result.address, since: result.since, until: result.until };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
110
163
|
// What reached the address and what was refused, without waiting: for when
|
|
111
164
|
// a wait comes back empty.
|
|
112
165
|
checkDelivery(address) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proxymail-qa",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Disposable test inboxes for Playwright, Cypress and scripts: create an address, then wait for its verification code or link.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Proxy Mail QA <hello@proxymail.qa> (https://proxymail.qa)",
|