@actionlogementservices/wdio-test-context 1.0.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/.editorconfig +20 -0
- package/.jsdoc.json +35 -0
- package/.prettierrc +11 -0
- package/README.md +116 -0
- package/doc/images/badges/modifier-abstract.png +0 -0
- package/doc/images/badges/modifier-abstract.svg +10 -0
- package/doc/images/badges/modifier-default.png +0 -0
- package/doc/images/badges/modifier-default.svg +10 -0
- package/doc/images/badges/modifier-private.png +0 -0
- package/doc/images/badges/modifier-private.svg +10 -0
- package/doc/images/badges/modifier-protected.png +0 -0
- package/doc/images/badges/modifier-protected.svg +10 -0
- package/doc/images/badges/modifier-public.png +0 -0
- package/doc/images/badges/modifier-public.svg +10 -0
- package/doc/images/badges/modifier-readonly.png +0 -0
- package/doc/images/badges/modifier-readonly.svg +10 -0
- package/doc/images/badges/modifier-static.png +0 -0
- package/doc/images/badges/modifier-static.svg +10 -0
- package/doc/src-page-objects_guerrillamail.page.md +69 -0
- package/doc/src-page-objects_maildrop.page.md +57 -0
- package/doc/src-page-objects_page.md +484 -0
- package/doc/src-page-objects_yopmail.page.md +57 -0
- package/doc/src-wdio_ado-reporter.md +93 -0
- package/doc/src-wdio_test-context-worker-service.md +48 -0
- package/doc/src_ado-client.md +55 -0
- package/doc/src_logger.md +183 -0
- package/doc/src_mail-service.md +54 -0
- package/doc/src_pdf-generator.md +35 -0
- package/doc/src_test-context.md +173 -0
- package/doc/toc.md +22 -0
- package/eslint.config.js +100 -0
- package/jsconfig.json +14 -0
- package/package.json +58 -0
- package/src/ado-client.js +96 -0
- package/src/index.js +8 -0
- package/src/logger.js +125 -0
- package/src/mail-service.js +81 -0
- package/src/page-objects/guerrillamail.page.js +144 -0
- package/src/page-objects/index.js +3 -0
- package/src/page-objects/maildrop.page.js +97 -0
- package/src/page-objects/page.js +463 -0
- package/src/page-objects/yopmail.page.js +102 -0
- package/src/pdf-generator.js +61 -0
- package/src/test-context.js +248 -0
- package/src/types.d.ts +60 -0
- package/src/wdio/ado-reporter.js +111 -0
- package/src/wdio/test-context-worker-service.js +88 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure DevOps rest client to push test results.
|
|
3
|
+
* @module
|
|
4
|
+
* @category internal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { WebApi, getPersonalAccessTokenHandler, getBearerHandler } from 'azure-devops-node-api';
|
|
8
|
+
|
|
9
|
+
import { logger } from './logger.js';
|
|
10
|
+
|
|
11
|
+
/** @typedef { import('azure-devops-node-api/TestApi.d.ts').ITestApi } ITestApi */
|
|
12
|
+
/** @typedef { { token: string, url: string, project: string } } ConnectionInfo */
|
|
13
|
+
/** @typedef { { testAgent: ITestApi } } Apis */
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Omit<import('azure-devops-node-api/interfaces/TestInterfaces.d.ts').RunCreateModel, "plan" | "configurationIds"> & import('azure-devops-node-api/interfaces/TestInterfaces.d.ts').RunUpdateModel & { results: import('azure-devops-node-api/interfaces/TestInterfaces.d.ts').TestCaseResult[]}} RunModel
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** @type {(input: string)=> boolean} */
|
|
19
|
+
const isNullOrEmpty = input => !input || !input.trim();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Retrieves Azure DevOps connection information.
|
|
23
|
+
* @returns {ConnectionInfo}
|
|
24
|
+
*/
|
|
25
|
+
function getConnectionInfo() {
|
|
26
|
+
return {
|
|
27
|
+
token: process.env.SYSTEM_ACCESSTOKEN || process.env.TOKEN,
|
|
28
|
+
url: process.env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI,
|
|
29
|
+
project: process.env.SYSTEM_TEAMPROJECT
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gets all necessary REST API clients.
|
|
35
|
+
* See https://github.com/Microsoft/azure-devops-node-api and https://docs.microsoft.com/en-us/rest/api/azure/devops/
|
|
36
|
+
* @param {ConnectionInfo} connectionInfo
|
|
37
|
+
* @returns {Promise<Apis>}
|
|
38
|
+
*/
|
|
39
|
+
async function getApis(connectionInfo) {
|
|
40
|
+
if (isNullOrEmpty(connectionInfo.token))
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Impossible de récupérer l'access token de l'agent via la variable d'environnement SYSTEM_ACCESSTOKEN.`
|
|
43
|
+
);
|
|
44
|
+
if (isNullOrEmpty(connectionInfo.url))
|
|
45
|
+
throw new Error(
|
|
46
|
+
`Impossible de récupérer l'url Azure DevOps via la variable d'environnement SYSTEM_TEAMFOUNDATIONCOLLECTIONURI.`
|
|
47
|
+
);
|
|
48
|
+
if (isNullOrEmpty(connectionInfo.project))
|
|
49
|
+
throw new Error(
|
|
50
|
+
`Impossible de récupérer le projet Azure DevOps via la variable d'environnement SYSTEM_TEAMPROJECT.`
|
|
51
|
+
);
|
|
52
|
+
const patAuthentication = !isNullOrEmpty(process.env.TOKEN);
|
|
53
|
+
const connection = new WebApi(
|
|
54
|
+
connectionInfo.url,
|
|
55
|
+
patAuthentication
|
|
56
|
+
? getPersonalAccessTokenHandler(connectionInfo.token)
|
|
57
|
+
: getBearerHandler(connectionInfo.token)
|
|
58
|
+
);
|
|
59
|
+
const testAgent = await connection.getTestApi();
|
|
60
|
+
return { testAgent };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Creates the Azure DevOps TestRun.
|
|
65
|
+
* @param {RunModel} testRun
|
|
66
|
+
*/
|
|
67
|
+
async function createAdoTestRun({ name, startDate, comment, results, state, completedDate, build }) {
|
|
68
|
+
try {
|
|
69
|
+
// get REST API clients
|
|
70
|
+
const connectionInfo = getConnectionInfo();
|
|
71
|
+
const apis = await getApis(connectionInfo);
|
|
72
|
+
const testRun = await apis.testAgent.createTestRun(
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
{ automated: true, name, startDate, build, state: 'InProgress', comment },
|
|
75
|
+
connectionInfo.project
|
|
76
|
+
);
|
|
77
|
+
if (testRun === null) throw new Error('Vérifier les droits.');
|
|
78
|
+
await apis.testAgent.addTestResultsToTestRun(results, connectionInfo.project, testRun.id);
|
|
79
|
+
// en cas de suite Aborted il faut déjà la sauvegarder en Completed avant sinon tous les tests sont marqués à Failed
|
|
80
|
+
await apis.testAgent.updateTestRun(
|
|
81
|
+
{ state: 'Completed', completedDate },
|
|
82
|
+
connectionInfo.project,
|
|
83
|
+
testRun.id
|
|
84
|
+
);
|
|
85
|
+
if (state === 'Aborted')
|
|
86
|
+
await apis.testAgent.updateTestRun(
|
|
87
|
+
{ state: 'Aborted', completedDate },
|
|
88
|
+
connectionInfo.project,
|
|
89
|
+
testRun.id
|
|
90
|
+
);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
logger.detailError(error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { createAdoTestRun };
|
package/src/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { AdoReporter } from './wdio/ado-reporter.js';
|
|
2
|
+
export { default as TestContextWorkerService } from './wdio/test-context-worker-service.js';
|
|
3
|
+
|
|
4
|
+
export { default as BasePage } from './page-objects/page.js';
|
|
5
|
+
|
|
6
|
+
export { default as pdfGenerator } from './pdf-generator.js';
|
|
7
|
+
|
|
8
|
+
export { TestContext } from './test-context.js';
|
package/src/logger.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal logger.
|
|
3
|
+
* @module
|
|
4
|
+
* @category internal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* eslint-disable no-console */
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
|
|
10
|
+
const noop = () => {};
|
|
11
|
+
/** console implementation @type {(message: string) => void} */
|
|
12
|
+
const logError = message => console.error(chalk.red(message));
|
|
13
|
+
/** console implementation @type {(message: string) => void} */
|
|
14
|
+
const logWarn = message => console.warn(chalk.yellow(message));
|
|
15
|
+
/** console implementation @type {(message: string) => void} */
|
|
16
|
+
const logInfo = message => console.info(chalk.bold.green(message));
|
|
17
|
+
/** console implementation @type {(message: string) => void} */
|
|
18
|
+
const logDebug = message => console.debug(chalk.blueBright.italic(message));
|
|
19
|
+
/** console implementation @type {(message: string) => void} */
|
|
20
|
+
const log = message => console.log(message);
|
|
21
|
+
|
|
22
|
+
/** @type {(message: string) => string} */
|
|
23
|
+
const bold = text => chalk.bold(text);
|
|
24
|
+
|
|
25
|
+
const level = {
|
|
26
|
+
none: 0,
|
|
27
|
+
error: 1,
|
|
28
|
+
warn: 2,
|
|
29
|
+
info: 3,
|
|
30
|
+
debug: 4
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
class Logger {
|
|
34
|
+
/** @type {Map<'error' | 'warn' | 'info' | 'debug' | 'log', (message: string) => void>} */ _logMethodFactory;
|
|
35
|
+
/** @type {Number} */ _level;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Implements an internal Logger plugged on console.
|
|
39
|
+
* @param {import('./types').LogLevel} logLevel logging level
|
|
40
|
+
*/
|
|
41
|
+
constructor(logLevel) {
|
|
42
|
+
this.setLogLevel(logLevel);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Sets the logging level.
|
|
47
|
+
* @param {import('./types').LogLevel} logLevel logging level
|
|
48
|
+
*/
|
|
49
|
+
setLogLevel(logLevel) {
|
|
50
|
+
this._level = level[logLevel] ?? level.none;
|
|
51
|
+
this._logMethodFactory = new Map();
|
|
52
|
+
this._logMethodFactory.set('error', this._level >= level.error ? logError : noop);
|
|
53
|
+
this._logMethodFactory.set('warn', this._level >= level.warn ? logWarn : noop);
|
|
54
|
+
this._logMethodFactory.set('info', this._level >= level.info ? logInfo : noop);
|
|
55
|
+
this._logMethodFactory.set('debug', this._level >= level.debug ? logDebug : noop);
|
|
56
|
+
this._logMethodFactory.set('log', this._level >= level.debug ? log : noop);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Logs an **informational** message.
|
|
61
|
+
* @param {string} message the message to log
|
|
62
|
+
*/
|
|
63
|
+
info(message) {
|
|
64
|
+
this._logMethodFactory.get('info')(message);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Logs a message.
|
|
69
|
+
* @param {string} message the message to log
|
|
70
|
+
*/
|
|
71
|
+
log(message) {
|
|
72
|
+
this._logMethodFactory.get('log')(message);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Logs a **warning** message.
|
|
77
|
+
* @param {string} message the message to log
|
|
78
|
+
*/
|
|
79
|
+
warn(message) {
|
|
80
|
+
this._logMethodFactory.get('warn')(message);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Logs an **error** message.
|
|
85
|
+
* @param {string} message the message to log
|
|
86
|
+
*/
|
|
87
|
+
error(message) {
|
|
88
|
+
this._logMethodFactory.get('error')(message);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Logs a **debug** message
|
|
93
|
+
* @param {string} message the message to log
|
|
94
|
+
*/
|
|
95
|
+
debug(message) {
|
|
96
|
+
this._logMethodFactory.get('debug')(message);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Logs an **error** message based on the specified error object.
|
|
101
|
+
* @param {Error} detailedError the error object to log
|
|
102
|
+
*/
|
|
103
|
+
detailError(detailedError) {
|
|
104
|
+
if (this._level === level.none) return;
|
|
105
|
+
const { message, stack } = detailedError;
|
|
106
|
+
console.error('Error: ' + chalk.red.bold(message));
|
|
107
|
+
if (stack) console.error('Stack: ' + chalk.gray(stack));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Logs an **warning** message based on the specified error object.
|
|
112
|
+
* @param {string} text the text message to log
|
|
113
|
+
* @param {{ message: string, errorType: string }} meaningfulErrorInfo the meaningfull error info to log
|
|
114
|
+
*/
|
|
115
|
+
warnError(text, meaningfulErrorInfo) {
|
|
116
|
+
if (this._level < level.warn) return;
|
|
117
|
+
const { message, errorType } = meaningfulErrorInfo;
|
|
118
|
+
logWarn(`${text}${bold(errorType)}: ${message}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The common logger instance.
|
|
124
|
+
*/
|
|
125
|
+
export const logger = new Logger('error');
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Mail service** to send and retrieve mail from various provider.
|
|
3
|
+
* Accessible through the **mailService property** of the TestContext instance.
|
|
4
|
+
* @module
|
|
5
|
+
* @category public
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import nodemailer from 'nodemailer';
|
|
9
|
+
|
|
10
|
+
import * as provider from './page-objects/index.js';
|
|
11
|
+
import { logger } from './logger.js';
|
|
12
|
+
|
|
13
|
+
/** @typedef {import('./types.js').MailProvider} MailProvider */
|
|
14
|
+
|
|
15
|
+
export class MailService {
|
|
16
|
+
/** disposable email provider @type {MailProvider} */ provider;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Implements a service that sends and retrieves emails with a given provider.
|
|
20
|
+
* @param {import('./types.js').MailProviderName} providerName disposable email provider name
|
|
21
|
+
*/
|
|
22
|
+
constructor(providerName) {
|
|
23
|
+
this.provider = provider[providerName].default;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Provider name
|
|
28
|
+
* @type {string}
|
|
29
|
+
*/
|
|
30
|
+
get name() {
|
|
31
|
+
return this.provider?.name;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Emails domains exposed by the provider.
|
|
36
|
+
* @type {string[]}
|
|
37
|
+
*/
|
|
38
|
+
get domains() {
|
|
39
|
+
return this.provider?.domains;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Sends a mail.
|
|
44
|
+
* @param {string} from sender
|
|
45
|
+
* @param {string} to recipient
|
|
46
|
+
* @param {string} subject subject of the mail
|
|
47
|
+
* @param {string} html html body string of the mail
|
|
48
|
+
* @returns {Promise<void>}
|
|
49
|
+
*/
|
|
50
|
+
async sendMessage(from, to, subject, html) {
|
|
51
|
+
const transporter = nodemailer.createTransport({ host: 'smtp.als.lan', secure: false, port: 25 });
|
|
52
|
+
await transporter.sendMail({ from, to, subject, html });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Waits for an email from the specified sender and containing the specified subject
|
|
57
|
+
* and gets its content.
|
|
58
|
+
* @param {string} email recipient email
|
|
59
|
+
* @param {string} from sender
|
|
60
|
+
* @param {string} subject subject of email
|
|
61
|
+
* @returns {Promise<string>} content of email
|
|
62
|
+
*/
|
|
63
|
+
async waitForMessage(email, from, subject) {
|
|
64
|
+
logger.debug('1/3 - Opening mailbox...');
|
|
65
|
+
await this.provider.openInbox(email);
|
|
66
|
+
logger.debug('2/3 - Looking for mails...');
|
|
67
|
+
const messages = await this.provider.getMessages();
|
|
68
|
+
logger.debug(` - ${messages.length} mails in inbox.`);
|
|
69
|
+
const correspondingIndex = messages.findIndex(
|
|
70
|
+
m =>
|
|
71
|
+
m.from.toLowerCase().includes(from.toLowerCase()) &&
|
|
72
|
+
m.subject.toLowerCase().includes(subject.toLowerCase())
|
|
73
|
+
);
|
|
74
|
+
if (correspondingIndex === -1) {
|
|
75
|
+
logger.warn(' No corresponding mail found!');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
logger.debug('3/3 - Mail found, extracting content...');
|
|
79
|
+
return this.provider.getMessageContent(correspondingIndex);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page-object on top of Guerilla Mail.
|
|
3
|
+
* @module
|
|
4
|
+
* @category internal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* global browser,$,$$ */
|
|
8
|
+
|
|
9
|
+
import Page from './page.js';
|
|
10
|
+
import { logger } from '../logger.js';
|
|
11
|
+
|
|
12
|
+
const mailFromGuerilla = 'no-reply@guerrillamail.com';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Implements a page-object on top of Guerilla Mail.
|
|
16
|
+
*/
|
|
17
|
+
class GuerillamailPage extends Page {
|
|
18
|
+
/** name of the provider */ name = 'Guerilla Mail';
|
|
19
|
+
|
|
20
|
+
/** domains exposed of the provider */
|
|
21
|
+
domains = [
|
|
22
|
+
'sharklasers.com',
|
|
23
|
+
'guerrillamail.info',
|
|
24
|
+
'grr.la',
|
|
25
|
+
'guerrillamail.biz',
|
|
26
|
+
'guerrillamail.com',
|
|
27
|
+
'guerrillamail.de',
|
|
28
|
+
'guerrillamail.net',
|
|
29
|
+
'guerrillamail.org',
|
|
30
|
+
'guerrillamailblock.com',
|
|
31
|
+
'pokemail.net',
|
|
32
|
+
'spam4.me'
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
css = {
|
|
36
|
+
text: {
|
|
37
|
+
inbox: '#content div.mailbox table tbody'
|
|
38
|
+
},
|
|
39
|
+
input: {
|
|
40
|
+
nom: '#inbox-id input'
|
|
41
|
+
},
|
|
42
|
+
button: {
|
|
43
|
+
nom: '#inbox-id',
|
|
44
|
+
set: 'button.save',
|
|
45
|
+
consent: 'div.fc-consent-root button[aria-label=Consent]'
|
|
46
|
+
},
|
|
47
|
+
options: {
|
|
48
|
+
domaines: '#gm-host-select option'
|
|
49
|
+
},
|
|
50
|
+
tbody: {
|
|
51
|
+
messages: '#email_list'
|
|
52
|
+
},
|
|
53
|
+
select: {
|
|
54
|
+
domaine: '#gm-host-select'
|
|
55
|
+
},
|
|
56
|
+
div: {
|
|
57
|
+
messages: '#email_list tr',
|
|
58
|
+
content: 'div.email_body',
|
|
59
|
+
popup: 'div.fc-consent-root'
|
|
60
|
+
},
|
|
61
|
+
td: {
|
|
62
|
+
from: 'td:nth-of-type(2)',
|
|
63
|
+
fromguerrilla: '#email_list tr:nth-of-type(1) td.td2',
|
|
64
|
+
subject: 'td:nth-of-type(3)'
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* WDIO logic to open the mailbox.
|
|
70
|
+
* @param {string} email disposable email
|
|
71
|
+
*/
|
|
72
|
+
async openInbox(email) {
|
|
73
|
+
await this.openNewTab('inbox', `https://www.guerrillamail.com/fr/inbox`);
|
|
74
|
+
const popup = await this.verifyElementExistsDuring(this.css.div.popup, 5);
|
|
75
|
+
if (popup) {
|
|
76
|
+
await this.click(this.css.button.consent);
|
|
77
|
+
logger.debug('Guerilla Mail popup detected');
|
|
78
|
+
}
|
|
79
|
+
const [alias, domain] = email.split('@');
|
|
80
|
+
await this.click(this.css.button.nom);
|
|
81
|
+
await this.fillInput(this.css.input.nom, alias);
|
|
82
|
+
await this.click(this.css.button.set);
|
|
83
|
+
await this.selectItem(this.css.select.domaine, domain);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* WDIO logic to retrieve domains exposed by the provider.
|
|
88
|
+
* @returns {Promise<string[]>}
|
|
89
|
+
*/
|
|
90
|
+
async retrieveDomains() {
|
|
91
|
+
// le tableau contenant tous les domaines
|
|
92
|
+
const domains = await this.getOptions(this.css.options.domaines);
|
|
93
|
+
return domains;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* WDIO logic to get emails.
|
|
98
|
+
* @return {Promise<{ from: string, subject: string}[]>}
|
|
99
|
+
*/
|
|
100
|
+
async getMessages() {
|
|
101
|
+
let noMessage = true;
|
|
102
|
+
do {
|
|
103
|
+
// on attend 1s avant de revérifier
|
|
104
|
+
await browser.pause(1000);
|
|
105
|
+
// on vérifie s'il y a des messages autre que celui de guerilla
|
|
106
|
+
const from = await $(this.css.td.fromguerrilla).getText();
|
|
107
|
+
noMessage = from === mailFromGuerilla;
|
|
108
|
+
} while (noMessage);
|
|
109
|
+
const froms = [];
|
|
110
|
+
const messagesCount = await $$(this.css.div.messages).length;
|
|
111
|
+
for (let index = 0; index < messagesCount; index++) {
|
|
112
|
+
const from = await $(`tr:nth-of-type(${index + 1}) td:nth-of-type(2)`).getText();
|
|
113
|
+
const subject = await $(`tr:nth-of-type(${index + 1}) td:nth-of-type(3)`).getText();
|
|
114
|
+
froms.push({ from, subject });
|
|
115
|
+
}
|
|
116
|
+
// // étrangement, ne fonctionne pas avec les tableaux
|
|
117
|
+
// const messages = await $$(this.css.div.messages).getElements();
|
|
118
|
+
// for (const message of messages) {
|
|
119
|
+
// const from = await message.$(this.css.td.from).getText();
|
|
120
|
+
// const subject = await message.$(this.css.td.subject).getText();
|
|
121
|
+
// froms.push({ from, subject });
|
|
122
|
+
// }
|
|
123
|
+
return froms;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* WDIO logic to get the specified message content.
|
|
128
|
+
* @param {number} index
|
|
129
|
+
* @returns {Promise<string>}
|
|
130
|
+
*/
|
|
131
|
+
async getMessageContent(index) {
|
|
132
|
+
// on attend que la zone contenant les messages soit prête
|
|
133
|
+
await $(this.css.div.messages).parentElement().waitForStable();
|
|
134
|
+
const messages = await $$(this.css.div.messages);
|
|
135
|
+
const message = messages[index];
|
|
136
|
+
await message.click();
|
|
137
|
+
const content = await $(this.css.div.content);
|
|
138
|
+
return content.getHTML({ includeSelectorTag: false });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const page = new GuerillamailPage();
|
|
143
|
+
|
|
144
|
+
export default page;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page-object on top of maildrop.
|
|
3
|
+
* @module
|
|
4
|
+
* @category internal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* global browser,$,$$ */
|
|
8
|
+
|
|
9
|
+
import Page from './page.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Implements a page-object on top of maildrop.
|
|
13
|
+
*/
|
|
14
|
+
class MaildropPage extends Page {
|
|
15
|
+
/** name of the provider */ name = 'maildrop';
|
|
16
|
+
|
|
17
|
+
/** domains exposed of the provider */ domains = ['maildrop.cc'];
|
|
18
|
+
|
|
19
|
+
css = {
|
|
20
|
+
text: {
|
|
21
|
+
inbox: '#content div.mailbox table tbody'
|
|
22
|
+
},
|
|
23
|
+
div: {
|
|
24
|
+
messageZone: 'main div.subhead',
|
|
25
|
+
messages: 'main div.message',
|
|
26
|
+
from: 'div:nth-of-type(1)',
|
|
27
|
+
subject: 'div:nth-of-type(3)',
|
|
28
|
+
content: 'html body'
|
|
29
|
+
},
|
|
30
|
+
input: {
|
|
31
|
+
name: 'main + section form input[placeholder=view-this-mailbox]'
|
|
32
|
+
},
|
|
33
|
+
button: {
|
|
34
|
+
view: 'main + section form button',
|
|
35
|
+
refresh: 'main button'
|
|
36
|
+
},
|
|
37
|
+
iframe: {
|
|
38
|
+
messages: 'iframe[srcdoc]'
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* WDIO logic to open the mailbox.
|
|
44
|
+
* @param {string} email disposable email
|
|
45
|
+
*/
|
|
46
|
+
async openInbox(email) {
|
|
47
|
+
await this.openNewTab('inbox', `https://maildrop.cc`);
|
|
48
|
+
const alias = email.split('@')[0];
|
|
49
|
+
// on clique dans le champ sinon le site change son contenu quand on clique sur le bouton View
|
|
50
|
+
await this.click(this.css.input.name);
|
|
51
|
+
await browser.pause(400);
|
|
52
|
+
await this.fillInput(this.css.input.name, alias);
|
|
53
|
+
await browser.pause(300);
|
|
54
|
+
await this.click(this.css.button.view);
|
|
55
|
+
await $(this.css.button.refresh).waitForExist();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* WDIO logic to get emails.
|
|
60
|
+
* @return {Promise<{ from: string, subject: string}[]>}
|
|
61
|
+
*/
|
|
62
|
+
async getMessages() {
|
|
63
|
+
let noMessage = true;
|
|
64
|
+
do {
|
|
65
|
+
// on attend 1,5s avant de cliquer sur refresh
|
|
66
|
+
await this.click(this.css.button.refresh);
|
|
67
|
+
// on attend que la zone contenant les messages soit prête
|
|
68
|
+
await $(this.css.div.messageZone).waitForDisplayed();
|
|
69
|
+
// on vérifie s'il y a des messages
|
|
70
|
+
noMessage = !(await this.verifyElementExists(this.css.div.messages));
|
|
71
|
+
if (noMessage) await browser.pause(1500);
|
|
72
|
+
} while (noMessage);
|
|
73
|
+
const messages = await $$(this.css.div.messages).getElements();
|
|
74
|
+
const froms = [];
|
|
75
|
+
for (const message of messages) {
|
|
76
|
+
const from = await message.$(this.css.div.from).getText();
|
|
77
|
+
const subject = await message.$(this.css.div.subject).getText();
|
|
78
|
+
froms.push({ from, subject });
|
|
79
|
+
}
|
|
80
|
+
return froms;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* WDIO logic to get the specified message content.
|
|
85
|
+
* @param {number} index
|
|
86
|
+
* @returns {Promise<string>}
|
|
87
|
+
*/
|
|
88
|
+
async getMessageContent(index) {
|
|
89
|
+
await this.click(`${this.css.div.messages}:nth-of-type(${index + 1})`);
|
|
90
|
+
await this.switchToFrame(this.css.iframe.messages);
|
|
91
|
+
return this.getHtml(this.css.div.content);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const page = new MaildropPage();
|
|
96
|
+
|
|
97
|
+
export default page;
|