@rich-automation/lotto 0.1.3 → 0.1.5
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/lib/cjs/controllers/factory.js +3 -0
- package/lib/cjs/controllers/playwright/index.js +74 -0
- package/lib/cjs/controllers/playwright/playwright.page.js +91 -0
- package/lib/cjs/controllers/puppeteer/index.js +5 -1
- package/lib/cjs/controllers/puppeteer/puppeteer.page.js +6 -7
- package/lib/cjs/lottoService.js +3 -12
- package/lib/esm/controllers/factory.js +3 -0
- package/lib/esm/controllers/playwright/index.js +71 -0
- package/lib/esm/controllers/playwright/playwright.page.js +87 -0
- package/lib/esm/controllers/puppeteer/index.js +5 -1
- package/lib/esm/controllers/puppeteer/puppeteer.page.js +6 -7
- package/lib/esm/lottoService.js +3 -12
- package/lib/typescript/controllers/factory.d.ts +1 -1
- package/lib/typescript/controllers/playwright/index.d.ts +14 -0
- package/lib/typescript/controllers/playwright/playwright.page.d.ts +20 -0
- package/lib/typescript/controllers/puppeteer/puppeteer.page.d.ts +3 -3
- package/lib/typescript/types.d.ts +4 -3
- package/package.json +6 -2
- package/playwright.config.ts +66 -0
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createBrowserController = void 0;
|
|
4
4
|
const puppeteer_1 = require("./puppeteer");
|
|
5
|
+
const playwright_1 = require("./playwright");
|
|
5
6
|
function createBrowserController(name, configs, logger) {
|
|
6
7
|
switch (name) {
|
|
7
8
|
case 'puppeteer':
|
|
8
9
|
return new puppeteer_1.PuppeteerController(configs, logger);
|
|
10
|
+
case 'playwright':
|
|
11
|
+
return new playwright_1.PlaywrightController(configs, logger);
|
|
9
12
|
}
|
|
10
13
|
}
|
|
11
14
|
exports.createBrowserController = createBrowserController;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PlaywrightController = void 0;
|
|
13
|
+
const playwright_1 = require("playwright");
|
|
14
|
+
const deferred_1 = require("../../utils/deferred");
|
|
15
|
+
const playwright_page_1 = require("./playwright.page");
|
|
16
|
+
const constants_1 = require("../../constants");
|
|
17
|
+
class PlaywrightController {
|
|
18
|
+
constructor(configs, logger) {
|
|
19
|
+
this.getBrowser = () => __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
const p = (0, deferred_1.deferred)();
|
|
21
|
+
if (this.browser) {
|
|
22
|
+
p.resolve(this.browser);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
let retry = 0;
|
|
26
|
+
const interval = setInterval(() => {
|
|
27
|
+
if (constants_1.CONST.BROWSER_INIT_RETRY_COUNT < retry) {
|
|
28
|
+
clearInterval(interval);
|
|
29
|
+
p.reject(new Error('Browser is not initialized'));
|
|
30
|
+
}
|
|
31
|
+
else if (this.browser) {
|
|
32
|
+
clearInterval(interval);
|
|
33
|
+
p.resolve(this.browser);
|
|
34
|
+
}
|
|
35
|
+
retry++;
|
|
36
|
+
}, constants_1.CONST.BROWSER_INIT_RETRY_TIMEOUT);
|
|
37
|
+
}
|
|
38
|
+
return p.promise;
|
|
39
|
+
});
|
|
40
|
+
this.focus = (pageIndex = -1) => __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
const browser = yield this.getBrowser();
|
|
42
|
+
const pages = browser.pages();
|
|
43
|
+
if (pages.length === 0) {
|
|
44
|
+
const page = yield browser.newPage();
|
|
45
|
+
return new playwright_page_1.PlaywrightPage(browser, page, this.logger);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const isWithinRange = Math.max(0, Math.min(pageIndex, pages.length - 1)) === pageIndex;
|
|
49
|
+
const page = pages.at(isWithinRange ? pageIndex : -1);
|
|
50
|
+
if (!page)
|
|
51
|
+
throw new Error('Page is not found');
|
|
52
|
+
return new playwright_page_1.PlaywrightPage(browser, page, this.logger);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
this.close = () => __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
const browser = yield this.getBrowser();
|
|
57
|
+
return browser.close();
|
|
58
|
+
});
|
|
59
|
+
this.cleanPages = (remainingPageIndex) => __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
const browser = yield this.getBrowser();
|
|
61
|
+
const pages = browser.pages();
|
|
62
|
+
const promises = pages.map((page, index) => __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
if (!remainingPageIndex.includes(index)) {
|
|
64
|
+
return page.close();
|
|
65
|
+
}
|
|
66
|
+
}));
|
|
67
|
+
yield Promise.all(promises);
|
|
68
|
+
});
|
|
69
|
+
this.configs = configs;
|
|
70
|
+
this.logger = logger;
|
|
71
|
+
playwright_1.chromium.launch(this.configs).then((browser) => __awaiter(this, void 0, void 0, function* () { return (this.browser = yield browser.newContext()); }));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.PlaywrightController = PlaywrightController;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PlaywrightPage = void 0;
|
|
13
|
+
const deferred_1 = require("../../utils/deferred");
|
|
14
|
+
const lazyRun_1 = require("../../utils/lazyRun");
|
|
15
|
+
class PlaywrightPage {
|
|
16
|
+
constructor(context, page, logger) {
|
|
17
|
+
this.context = context;
|
|
18
|
+
this.page = page;
|
|
19
|
+
this.logger = logger;
|
|
20
|
+
}
|
|
21
|
+
url() {
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
return this.page.url();
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
goto(url) {
|
|
27
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
yield this.page.goto(url, { waitUntil: 'load' });
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
fill(selector, value) {
|
|
32
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
yield this.page.type(selector, value.toString());
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
click(selector, domDirect = false) {
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
if (domDirect) {
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
yield this.page.evaluate(s => document.querySelector(s).click(), selector);
|
|
42
|
+
yield this.wait(250);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
yield this.page.click(selector, { timeout: 0 });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
select(selector, value) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
yield this.page.selectOption(selector, value);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
querySelectorAll(selector, callback) {
|
|
55
|
+
return this.page.$$eval(selector, callback);
|
|
56
|
+
}
|
|
57
|
+
getCookies() {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
const cookies = yield this.context.cookies();
|
|
60
|
+
return JSON.stringify(cookies);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
setCookies(cookies) {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
const cookieParams = JSON.parse(cookies);
|
|
66
|
+
yield this.context.addCookies(cookieParams);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
wait(param) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
const p = (0, deferred_1.deferred)();
|
|
72
|
+
if (param === 'idle') {
|
|
73
|
+
yield this.page.waitForNavigation({ waitUntil: 'networkidle' });
|
|
74
|
+
p.resolve();
|
|
75
|
+
}
|
|
76
|
+
if (param === 'load') {
|
|
77
|
+
yield this.page.waitForNavigation({ waitUntil: 'load' });
|
|
78
|
+
p.resolve();
|
|
79
|
+
}
|
|
80
|
+
if (typeof param === 'number') {
|
|
81
|
+
yield (0, lazyRun_1.lazyRun)(() => __awaiter(this, void 0, void 0, function* () { return p.resolve(); }), param);
|
|
82
|
+
}
|
|
83
|
+
return p.promise;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
on(event, callback) {
|
|
87
|
+
this.page.on(event, callback);
|
|
88
|
+
return () => this.page.off(event, callback);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.PlaywrightPage = PlaywrightPage;
|
|
@@ -71,7 +71,11 @@ class PuppeteerController {
|
|
|
71
71
|
});
|
|
72
72
|
this.configs = configs;
|
|
73
73
|
this.logger = logger;
|
|
74
|
-
puppeteer_1.default
|
|
74
|
+
puppeteer_1.default
|
|
75
|
+
.launch(Object.assign(Object.assign({}, this.configs), { headless: this.configs.headless === true ? 'new' : this.configs.headless }))
|
|
76
|
+
.then((browser) => __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
this.browser = browser;
|
|
78
|
+
}));
|
|
75
79
|
}
|
|
76
80
|
}
|
|
77
81
|
exports.PuppeteerController = PuppeteerController;
|
|
@@ -16,7 +16,6 @@ class PuppeteerPage {
|
|
|
16
16
|
constructor(page, logger) {
|
|
17
17
|
this.page = page;
|
|
18
18
|
this.logger = logger;
|
|
19
|
-
this.page = page;
|
|
20
19
|
}
|
|
21
20
|
url() {
|
|
22
21
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -33,13 +32,13 @@ class PuppeteerPage {
|
|
|
33
32
|
yield this.page.type(selector, value.toString());
|
|
34
33
|
});
|
|
35
34
|
}
|
|
36
|
-
click(selector,
|
|
37
|
-
var _a;
|
|
35
|
+
click(selector, domDirect = false) {
|
|
38
36
|
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
if (domDirect) {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
yield this.page.evaluate(s => document.querySelector(s).click(), selector);
|
|
41
|
+
yield this.wait(250);
|
|
43
42
|
}
|
|
44
43
|
else {
|
|
45
44
|
yield this.page.click(selector);
|
package/lib/cjs/lottoService.js
CHANGED
|
@@ -29,6 +29,7 @@ const validatePurchaseAvailability_1 = require("./utils/validatePurchaseAvailabi
|
|
|
29
29
|
const getCheckWinningLink_1 = require("./utils/getCheckWinningLink");
|
|
30
30
|
class LottoService {
|
|
31
31
|
constructor(configs) {
|
|
32
|
+
var _a;
|
|
32
33
|
this.context = {
|
|
33
34
|
authenticated: false
|
|
34
35
|
};
|
|
@@ -117,17 +118,7 @@ class LottoService {
|
|
|
117
118
|
this.logger.debug('[purchase]', 'click purchase button');
|
|
118
119
|
yield page.click(selectors_1.SELECTORS.PURCHASE_BTN);
|
|
119
120
|
this.logger.debug('[purchase]', 'click purchase confirm button');
|
|
120
|
-
|
|
121
|
-
yield page.click(selectors_1.SELECTORS.PURCHASE_CONFIRM_BTN, true);
|
|
122
|
-
}
|
|
123
|
-
catch (e) {
|
|
124
|
-
this.logger.debug('[purchase]', 'purchase confirm failure', e);
|
|
125
|
-
this.logger.debug('[purchase]', 'print node');
|
|
126
|
-
yield page.querySelectorAll(selectors_1.SELECTORS.PURCHASE_CONFIRM_BTN, elems => {
|
|
127
|
-
this.logger.debug('[purchase]', elems);
|
|
128
|
-
});
|
|
129
|
-
throw e;
|
|
130
|
-
}
|
|
121
|
+
yield page.click(selectors_1.SELECTORS.PURCHASE_CONFIRM_BTN);
|
|
131
122
|
yield page.wait(1000);
|
|
132
123
|
// game result
|
|
133
124
|
this.logger.debug('[purchase]', 'print result');
|
|
@@ -146,7 +137,7 @@ class LottoService {
|
|
|
146
137
|
return (0, getCheckWinningLink_1.getCheckWinningLink)(round, numbers);
|
|
147
138
|
};
|
|
148
139
|
this.logger = new logger_1.default(configs === null || configs === void 0 ? void 0 : configs.logLevel, '[LottoService]');
|
|
149
|
-
this.browserController = (0, factory_1.createBrowserController)(
|
|
140
|
+
this.browserController = (0, factory_1.createBrowserController)((_a = configs === null || configs === void 0 ? void 0 : configs.controller) !== null && _a !== void 0 ? _a : 'playwright', Object.assign({ defaultViewport: { width: 1080, height: 1024 } }, configs), this.logger);
|
|
150
141
|
}
|
|
151
142
|
}
|
|
152
143
|
exports.LottoService = LottoService;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { PuppeteerController } from './puppeteer';
|
|
2
|
+
import { PlaywrightController } from './playwright';
|
|
2
3
|
export function createBrowserController(name, configs, logger) {
|
|
3
4
|
switch (name) {
|
|
4
5
|
case 'puppeteer':
|
|
5
6
|
return new PuppeteerController(configs, logger);
|
|
7
|
+
case 'playwright':
|
|
8
|
+
return new PlaywrightController(configs, logger);
|
|
6
9
|
}
|
|
7
10
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { deferred } from '../../utils/deferred';
|
|
12
|
+
import { PlaywrightPage } from './playwright.page';
|
|
13
|
+
import { CONST } from '../../constants';
|
|
14
|
+
import {} from '../../logger';
|
|
15
|
+
export class PlaywrightController {
|
|
16
|
+
constructor(configs, logger) {
|
|
17
|
+
this.getBrowser = () => __awaiter(this, void 0, void 0, function* () {
|
|
18
|
+
const p = deferred();
|
|
19
|
+
if (this.browser) {
|
|
20
|
+
p.resolve(this.browser);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
let retry = 0;
|
|
24
|
+
const interval = setInterval(() => {
|
|
25
|
+
if (CONST.BROWSER_INIT_RETRY_COUNT < retry) {
|
|
26
|
+
clearInterval(interval);
|
|
27
|
+
p.reject(new Error('Browser is not initialized'));
|
|
28
|
+
}
|
|
29
|
+
else if (this.browser) {
|
|
30
|
+
clearInterval(interval);
|
|
31
|
+
p.resolve(this.browser);
|
|
32
|
+
}
|
|
33
|
+
retry++;
|
|
34
|
+
}, CONST.BROWSER_INIT_RETRY_TIMEOUT);
|
|
35
|
+
}
|
|
36
|
+
return p.promise;
|
|
37
|
+
});
|
|
38
|
+
this.focus = (pageIndex = -1) => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
const browser = yield this.getBrowser();
|
|
40
|
+
const pages = browser.pages();
|
|
41
|
+
if (pages.length === 0) {
|
|
42
|
+
const page = yield browser.newPage();
|
|
43
|
+
return new PlaywrightPage(browser, page, this.logger);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const isWithinRange = Math.max(0, Math.min(pageIndex, pages.length - 1)) === pageIndex;
|
|
47
|
+
const page = pages.at(isWithinRange ? pageIndex : -1);
|
|
48
|
+
if (!page)
|
|
49
|
+
throw new Error('Page is not found');
|
|
50
|
+
return new PlaywrightPage(browser, page, this.logger);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
this.close = () => __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
const browser = yield this.getBrowser();
|
|
55
|
+
return browser.close();
|
|
56
|
+
});
|
|
57
|
+
this.cleanPages = (remainingPageIndex) => __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
const browser = yield this.getBrowser();
|
|
59
|
+
const pages = browser.pages();
|
|
60
|
+
const promises = pages.map((page, index) => __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
if (!remainingPageIndex.includes(index)) {
|
|
62
|
+
return page.close();
|
|
63
|
+
}
|
|
64
|
+
}));
|
|
65
|
+
yield Promise.all(promises);
|
|
66
|
+
});
|
|
67
|
+
this.configs = configs;
|
|
68
|
+
this.logger = logger;
|
|
69
|
+
chromium.launch(this.configs).then((browser) => __awaiter(this, void 0, void 0, function* () { return (this.browser = yield browser.newContext()); }));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { deferred } from '../../utils/deferred';
|
|
11
|
+
import { lazyRun } from '../../utils/lazyRun';
|
|
12
|
+
export class PlaywrightPage {
|
|
13
|
+
constructor(context, page, logger) {
|
|
14
|
+
this.context = context;
|
|
15
|
+
this.page = page;
|
|
16
|
+
this.logger = logger;
|
|
17
|
+
}
|
|
18
|
+
url() {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
return this.page.url();
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
goto(url) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
yield this.page.goto(url, { waitUntil: 'load' });
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
fill(selector, value) {
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
yield this.page.type(selector, value.toString());
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
click(selector, domDirect = false) {
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
if (domDirect) {
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
yield this.page.evaluate(s => document.querySelector(s).click(), selector);
|
|
39
|
+
yield this.wait(250);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
yield this.page.click(selector, { timeout: 0 });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
select(selector, value) {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
yield this.page.selectOption(selector, value);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
querySelectorAll(selector, callback) {
|
|
52
|
+
return this.page.$$eval(selector, callback);
|
|
53
|
+
}
|
|
54
|
+
getCookies() {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
const cookies = yield this.context.cookies();
|
|
57
|
+
return JSON.stringify(cookies);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
setCookies(cookies) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
const cookieParams = JSON.parse(cookies);
|
|
63
|
+
yield this.context.addCookies(cookieParams);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
wait(param) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
const p = deferred();
|
|
69
|
+
if (param === 'idle') {
|
|
70
|
+
yield this.page.waitForNavigation({ waitUntil: 'networkidle' });
|
|
71
|
+
p.resolve();
|
|
72
|
+
}
|
|
73
|
+
if (param === 'load') {
|
|
74
|
+
yield this.page.waitForNavigation({ waitUntil: 'load' });
|
|
75
|
+
p.resolve();
|
|
76
|
+
}
|
|
77
|
+
if (typeof param === 'number') {
|
|
78
|
+
yield lazyRun(() => __awaiter(this, void 0, void 0, function* () { return p.resolve(); }), param);
|
|
79
|
+
}
|
|
80
|
+
return p.promise;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
on(event, callback) {
|
|
84
|
+
this.page.on(event, callback);
|
|
85
|
+
return () => this.page.off(event, callback);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -66,6 +66,10 @@ export class PuppeteerController {
|
|
|
66
66
|
});
|
|
67
67
|
this.configs = configs;
|
|
68
68
|
this.logger = logger;
|
|
69
|
-
puppeteer
|
|
69
|
+
puppeteer
|
|
70
|
+
.launch(Object.assign(Object.assign({}, this.configs), { headless: this.configs.headless === true ? 'new' : this.configs.headless }))
|
|
71
|
+
.then((browser) => __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
this.browser = browser;
|
|
73
|
+
}));
|
|
70
74
|
}
|
|
71
75
|
}
|
|
@@ -14,7 +14,6 @@ export class PuppeteerPage {
|
|
|
14
14
|
constructor(page, logger) {
|
|
15
15
|
this.page = page;
|
|
16
16
|
this.logger = logger;
|
|
17
|
-
this.page = page;
|
|
18
17
|
}
|
|
19
18
|
url() {
|
|
20
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -31,13 +30,13 @@ export class PuppeteerPage {
|
|
|
31
30
|
yield this.page.type(selector, value.toString());
|
|
32
31
|
});
|
|
33
32
|
}
|
|
34
|
-
click(selector,
|
|
35
|
-
var _a;
|
|
33
|
+
click(selector, domDirect = false) {
|
|
36
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
if (domDirect) {
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
yield this.page.evaluate(s => document.querySelector(s).click(), selector);
|
|
39
|
+
yield this.wait(250);
|
|
41
40
|
}
|
|
42
41
|
else {
|
|
43
42
|
yield this.page.click(selector);
|
package/lib/esm/lottoService.js
CHANGED
|
@@ -23,6 +23,7 @@ import { validatePurchaseAvailability } from './utils/validatePurchaseAvailabili
|
|
|
23
23
|
import { getCheckWinningLink } from './utils/getCheckWinningLink';
|
|
24
24
|
export class LottoService {
|
|
25
25
|
constructor(configs) {
|
|
26
|
+
var _a;
|
|
26
27
|
this.context = {
|
|
27
28
|
authenticated: false
|
|
28
29
|
};
|
|
@@ -111,17 +112,7 @@ export class LottoService {
|
|
|
111
112
|
this.logger.debug('[purchase]', 'click purchase button');
|
|
112
113
|
yield page.click(SELECTORS.PURCHASE_BTN);
|
|
113
114
|
this.logger.debug('[purchase]', 'click purchase confirm button');
|
|
114
|
-
|
|
115
|
-
yield page.click(SELECTORS.PURCHASE_CONFIRM_BTN, true);
|
|
116
|
-
}
|
|
117
|
-
catch (e) {
|
|
118
|
-
this.logger.debug('[purchase]', 'purchase confirm failure', e);
|
|
119
|
-
this.logger.debug('[purchase]', 'print node');
|
|
120
|
-
yield page.querySelectorAll(SELECTORS.PURCHASE_CONFIRM_BTN, elems => {
|
|
121
|
-
this.logger.debug('[purchase]', elems);
|
|
122
|
-
});
|
|
123
|
-
throw e;
|
|
124
|
-
}
|
|
115
|
+
yield page.click(SELECTORS.PURCHASE_CONFIRM_BTN);
|
|
125
116
|
yield page.wait(1000);
|
|
126
117
|
// game result
|
|
127
118
|
this.logger.debug('[purchase]', 'print result');
|
|
@@ -140,6 +131,6 @@ export class LottoService {
|
|
|
140
131
|
return getCheckWinningLink(round, numbers);
|
|
141
132
|
};
|
|
142
133
|
this.logger = new Logger(configs === null || configs === void 0 ? void 0 : configs.logLevel, '[LottoService]');
|
|
143
|
-
this.browserController = createBrowserController(
|
|
134
|
+
this.browserController = createBrowserController((_a = configs === null || configs === void 0 ? void 0 : configs.controller) !== null && _a !== void 0 ? _a : 'playwright', Object.assign({ defaultViewport: { width: 1080, height: 1024 } }, configs), this.logger);
|
|
144
135
|
}
|
|
145
136
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { BrowserConfigs, BrowserControllerInterface } from '../types';
|
|
2
2
|
import type { LoggerInterface } from '../logger';
|
|
3
|
-
export declare function createBrowserController(name: 'puppeteer', configs: BrowserConfigs, logger: LoggerInterface): BrowserControllerInterface;
|
|
3
|
+
export declare function createBrowserController(name: 'puppeteer' | 'playwright', configs: BrowserConfigs, logger: LoggerInterface): BrowserControllerInterface;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BrowserConfigs, BrowserControllerInterface } from '../../types';
|
|
2
|
+
import type { BrowserContext } from 'playwright';
|
|
3
|
+
import { PlaywrightPage } from './playwright.page';
|
|
4
|
+
import { type LoggerInterface } from '../../logger';
|
|
5
|
+
export declare class PlaywrightController implements BrowserControllerInterface {
|
|
6
|
+
configs: BrowserConfigs;
|
|
7
|
+
logger: LoggerInterface;
|
|
8
|
+
browser: BrowserContext;
|
|
9
|
+
constructor(configs: BrowserConfigs, logger: LoggerInterface);
|
|
10
|
+
private getBrowser;
|
|
11
|
+
focus: (pageIndex?: number) => Promise<PlaywrightPage>;
|
|
12
|
+
close: () => Promise<void>;
|
|
13
|
+
cleanPages: (remainingPageIndex: number[]) => Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BrowserPageEvents, BrowserPageInterface, FakeDOMElement, StringifiedCookies } from '../../types';
|
|
2
|
+
import type { Page } from 'playwright-core';
|
|
3
|
+
import type { LoggerInterface } from '../../logger';
|
|
4
|
+
import type { BrowserContext } from 'playwright';
|
|
5
|
+
export declare class PlaywrightPage implements BrowserPageInterface {
|
|
6
|
+
context: BrowserContext;
|
|
7
|
+
page: Page;
|
|
8
|
+
logger?: LoggerInterface;
|
|
9
|
+
constructor(context: BrowserContext, page: Page, logger?: LoggerInterface);
|
|
10
|
+
url(): Promise<string>;
|
|
11
|
+
goto(url: string): Promise<void>;
|
|
12
|
+
fill(selector: string, value: string | number): Promise<void>;
|
|
13
|
+
click(selector: string, domDirect?: boolean): Promise<void>;
|
|
14
|
+
select(selector: string, value: string): Promise<void>;
|
|
15
|
+
querySelectorAll<T>(selector: string, callback: (elems: FakeDOMElement[]) => T): Promise<T>;
|
|
16
|
+
getCookies(): Promise<string>;
|
|
17
|
+
setCookies(cookies: StringifiedCookies): Promise<void>;
|
|
18
|
+
wait(param: 'idle' | 'load' | number): Promise<void>;
|
|
19
|
+
on(event: BrowserPageEvents, callback: (...args: unknown[]) => void): () => Page;
|
|
20
|
+
}
|
|
@@ -3,12 +3,12 @@ import { Page } from 'puppeteer';
|
|
|
3
3
|
import type { LoggerInterface } from '../../logger';
|
|
4
4
|
export declare class PuppeteerPage implements BrowserPageInterface {
|
|
5
5
|
page: Page;
|
|
6
|
-
logger?: LoggerInterface
|
|
7
|
-
constructor(page: Page, logger?: LoggerInterface
|
|
6
|
+
logger?: LoggerInterface;
|
|
7
|
+
constructor(page: Page, logger?: LoggerInterface);
|
|
8
8
|
url(): Promise<string>;
|
|
9
9
|
goto(url: string): Promise<void>;
|
|
10
10
|
fill(selector: string, value: string | number): Promise<void>;
|
|
11
|
-
click(selector: string,
|
|
11
|
+
click(selector: string, domDirect?: boolean): Promise<void>;
|
|
12
12
|
select(selector: string, value: string): Promise<void>;
|
|
13
13
|
querySelectorAll<T>(selector: string, callback: (elems: FakeDOMElement[]) => T): Promise<T>;
|
|
14
14
|
getCookies(): Promise<string>;
|
|
@@ -11,8 +11,9 @@ export interface LottoServiceInterface {
|
|
|
11
11
|
getCheckWinningLink(round: number, numbers: number[][]): string;
|
|
12
12
|
}
|
|
13
13
|
export interface BrowserConfigs {
|
|
14
|
+
controller?: 'puppeteer' | 'playwright';
|
|
14
15
|
logLevel?: LogLevel;
|
|
15
|
-
headless?: boolean
|
|
16
|
+
headless?: boolean;
|
|
16
17
|
defaultViewport?: {
|
|
17
18
|
width: number;
|
|
18
19
|
height: number;
|
|
@@ -30,7 +31,7 @@ export interface BrowserPageInterface {
|
|
|
30
31
|
url(): Promise<string>;
|
|
31
32
|
goto(url: string): Promise<void>;
|
|
32
33
|
fill(selector: string, value: string | number): Promise<void>;
|
|
33
|
-
click(selector: string,
|
|
34
|
+
click(selector: string, domDirect?: boolean): Promise<void>;
|
|
34
35
|
select(selector: string, value: string): Promise<void>;
|
|
35
36
|
querySelectorAll<T>(selector: string, callback: (elems: FakeDOMElement[]) => T): Promise<T>;
|
|
36
37
|
wait(time: number): Promise<void>;
|
|
@@ -45,7 +46,7 @@ export type FakeDOMElement = {
|
|
|
45
46
|
innerHTML: string;
|
|
46
47
|
children: FakeDOMElement[];
|
|
47
48
|
};
|
|
48
|
-
export type BrowserPageEvents = '
|
|
49
|
+
export type BrowserPageEvents = 'response';
|
|
49
50
|
export type Unsubscribe = () => void;
|
|
50
51
|
export type StringifiedCookies = string;
|
|
51
52
|
export type GetWinningNumbersResponse = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rich-automation/lotto",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Lotto module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"files": [
|
|
23
23
|
"lib",
|
|
24
24
|
"package.json",
|
|
25
|
+
"playwright.config.ts",
|
|
25
26
|
"README.md"
|
|
26
27
|
],
|
|
27
28
|
"packageManager": "yarn@1.22.19",
|
|
@@ -35,7 +36,8 @@
|
|
|
35
36
|
"build:esm": "tsc --project tsconfig.esm.json && echo '{\"type\": \"module\"}' > lib/esm/package.json",
|
|
36
37
|
"build:dts": "tsc --project tsconfig.json --emitDeclarationOnly --declaration --declarationDir lib/typescript",
|
|
37
38
|
"test": "jest --forceExit --detectOpenHandles",
|
|
38
|
-
"install:
|
|
39
|
+
"install:puppeteer": "node ./node_modules/puppeteer/install.js",
|
|
40
|
+
"install:playwright": "npx playwright install --with-deps",
|
|
39
41
|
"fix": "yarn fix:eslint && yarn fix:prettier",
|
|
40
42
|
"fix:eslint": "eslint --fix src --ext js,jsx,ts,tsx ",
|
|
41
43
|
"fix:prettier": "prettier --write \"src/**/*.{ts,tsx,js}\"",
|
|
@@ -47,12 +49,14 @@
|
|
|
47
49
|
"dependencies": {
|
|
48
50
|
"axios": "^1.3.5",
|
|
49
51
|
"dayjs": "^1.11.7",
|
|
52
|
+
"playwright": "^1.35.0",
|
|
50
53
|
"puppeteer": "^20.5.0"
|
|
51
54
|
},
|
|
52
55
|
"devDependencies": {
|
|
53
56
|
"@babel/core": "^7.21.4",
|
|
54
57
|
"@babel/preset-env": "^7.21.4",
|
|
55
58
|
"@babel/preset-typescript": "^7.21.4",
|
|
59
|
+
"@playwright/test": "^1.35.0",
|
|
56
60
|
"@types/jest": "^29.5.0",
|
|
57
61
|
"@typescript-eslint/eslint-plugin": "^5.58.0",
|
|
58
62
|
"@typescript-eslint/parser": "^5.58.0",
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read environment variables from file.
|
|
5
|
+
* https://github.com/motdotla/dotenv
|
|
6
|
+
*/
|
|
7
|
+
// require('dotenv').config();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* See https://playwright.dev/docs/test-configuration.
|
|
11
|
+
*/
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
testDir: './src/__tests__',
|
|
14
|
+
/* Run tests in files in parallel */
|
|
15
|
+
fullyParallel: true,
|
|
16
|
+
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
17
|
+
forbidOnly: !!process.env.CI,
|
|
18
|
+
/* Retry on CI only */
|
|
19
|
+
retries: process.env.CI ? 2 : 0,
|
|
20
|
+
/* Opt out of parallel tests on CI. */
|
|
21
|
+
workers: process.env.CI ? 1 : undefined,
|
|
22
|
+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
23
|
+
reporter: 'html',
|
|
24
|
+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
25
|
+
use: {
|
|
26
|
+
/* Base URL to use in actions like `await page.goto('/')`. */
|
|
27
|
+
// baseURL: 'http://127.0.0.1:3000',
|
|
28
|
+
|
|
29
|
+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
30
|
+
trace: 'on-first-retry',
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/* Configure projects for major browsers */
|
|
34
|
+
projects: [
|
|
35
|
+
{
|
|
36
|
+
name: 'Google Chrome',
|
|
37
|
+
use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
|
38
|
+
},
|
|
39
|
+
// {
|
|
40
|
+
// name: 'chromium',
|
|
41
|
+
// use: { ...devices['Desktop Chrome'] },
|
|
42
|
+
// },
|
|
43
|
+
/* Test against mobile viewports. */
|
|
44
|
+
// {
|
|
45
|
+
// name: 'Mobile Chrome',
|
|
46
|
+
// use: { ...devices['Pixel 5'] },
|
|
47
|
+
// },
|
|
48
|
+
// {
|
|
49
|
+
// name: 'Mobile Safari',
|
|
50
|
+
// use: { ...devices['iPhone 12'] },
|
|
51
|
+
// },
|
|
52
|
+
|
|
53
|
+
/* Test against branded browsers. */
|
|
54
|
+
// {
|
|
55
|
+
// name: 'Microsoft Edge',
|
|
56
|
+
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
|
57
|
+
// },
|
|
58
|
+
],
|
|
59
|
+
|
|
60
|
+
/* Run your local dev server before starting the tests */
|
|
61
|
+
// webServer: {
|
|
62
|
+
// command: 'npm run start',
|
|
63
|
+
// url: 'http://127.0.0.1:3000',
|
|
64
|
+
// reuseExistingServer: !process.env.CI,
|
|
65
|
+
// },
|
|
66
|
+
});
|