@ntlab/sipd-agr 3.3.0 → 3.5.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.
@@ -44,6 +44,16 @@ Cmd.addBool('help', '', 'Show program usage', false);
44
44
  */
45
45
  class Configuration {
46
46
 
47
+ defaults = {
48
+ mode: Sipd.DOWNLOAD,
49
+ url: 'https://sipd-ri.kemendagri.go.id',
50
+ year: new Date().getFullYear(),
51
+ username: null,
52
+ password: null,
53
+ dir: null,
54
+ skipDownload: ['no-download', false],
55
+ }
56
+
47
57
  /**
48
58
  * Constructor.
49
59
  *
@@ -55,25 +65,13 @@ class Configuration {
55
65
  if (fs.existsSync(filename)) {
56
66
  Object.assign(this, this.getConfig(filename));
57
67
  }
58
- for (const a of ['url', 'username', 'password', 'year', 'dir']) {
59
- const v = Cmd.get(a);
60
- if (v) {
61
- this[a] = v;
62
- }
63
- }
64
68
  if (fs.existsSync(filename)) {
65
69
  console.log('Configuration loaded from %s', filename);
66
70
  }
67
71
  if (!this.workdir) {
68
72
  this.workdir = rootDir;
69
73
  }
70
- if (Cmd.get('no-download')) {
71
- this.skipDownload = Cmd.get('no-download');
72
- }
73
- if (!this.mode) {
74
- this.mode = Cmd.get('mode') ? Cmd.get('mode') : Sipd.DOWNLOAD;
75
- }
76
-
74
+ this.checkDefaults();
77
75
  if (!this.username || !this.password) {
78
76
  console.log('Both username or password must be supplied!');
79
77
  return;
@@ -103,6 +101,22 @@ class Configuration {
103
101
  this.initialized = true;
104
102
  }
105
103
 
104
+ checkDefaults() {
105
+ for (const [k, v] of Object.entries(this.defaults)) {
106
+ const opt = Array.isArray(v) ? v[0] : k;
107
+ const defval = Array.isArray(v) ? v[1] : v;
108
+ // get value from command options
109
+ let value = Cmd.get(opt);
110
+ // fallback to default
111
+ if (value === null) {
112
+ value = defval;
113
+ }
114
+ if (value !== undefined && value !== null) {
115
+ this[k] = value;
116
+ }
117
+ }
118
+ }
119
+
106
120
  getConfig(filename) {
107
121
  let config = JSON.parse(fs.readFileSync(filename));
108
122
  if (config.ref) {
@@ -1,7 +1,5 @@
1
1
  {
2
- "url":"https://sipd-ri.kemendagri.go.id",
3
2
  "provinsi":"CHANGEME",
4
3
  "username":"CHANGEME",
5
- "password":"CHANGEME",
6
- "year":"2025"
4
+ "password":"CHANGEME"
7
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ntlab/sipd-agr",
3
- "version": "3.3.0",
3
+ "version": "3.5.0",
4
4
  "description": "SIPD RI Kemendagri Automation is a web automation using Selenium to help manage data such as budgeting download",
5
5
  "main": "main.js",
6
6
  "author": "Toha <tohenk@yahoo.com>",
package/sipd/index.js CHANGED
@@ -27,6 +27,7 @@ const Queue = require('@ntlab/work/queue');
27
27
  const SipdApp = require('./modules/app');
28
28
  const SipdSubkeg = require('./modules/subkeg');
29
29
  const SipdRefs = require('./modules/refs');
30
+ const { By, error } = require('selenium-webdriver');
30
31
  const debug = require('debug')('sipdagr:core');
31
32
 
32
33
  class Sipd extends WebRobot {
@@ -45,6 +46,7 @@ class Sipd extends WebRobot {
45
46
  this.app = new SipdApp(this);
46
47
  this.subkeg = new SipdSubkeg(this);
47
48
  this.refs = new SipdRefs(this);
49
+ super.constructor.expectErr(error.StaleElementReferenceError);
48
50
  }
49
51
 
50
52
  getWorks() {
@@ -197,19 +199,28 @@ class Sipd extends WebRobot {
197
199
  }
198
200
  return new Promise((resolve, reject) => {
199
201
  let el, presence = false;
202
+ let target;
203
+ if (data.data instanceof By) {
204
+ target = data.data.value;
205
+ } else if (data instanceof By) {
206
+ target = data.value;
207
+ } else {
208
+ target = data;
209
+ }
200
210
  const t = Date.now();
201
211
  const f = () => {
202
212
  this.works([
203
- [w => this.findElements(data)],
213
+ [w => this.isStale(data.el), w => data.el],
214
+ [w => this.findElements(data), w => !w.getRes(0)],
204
215
  [w => new Promise((resolve, reject) => {
205
216
  let wait = true;
206
217
  if (options.mode === this.WAIT_GONE && presence && w.res.length === 0) {
207
- debug(`element now is gone: ${data}`);
218
+ debug(`element ${target} now is gone`);
208
219
  el = w.res[0];
209
220
  wait = false;
210
221
  }
211
222
  if (options.mode === this.WAIT_PRESENCE && !presence && w.res.length === 1) {
212
- debug(`element now is presence: ${data}`);
223
+ debug(`element ${target} now is presence`);
213
224
  el = w.res[0];
214
225
  wait = false;
215
226
  }
@@ -221,17 +232,25 @@ class Sipd extends WebRobot {
221
232
  wait = false;
222
233
  }
223
234
  resolve(wait);
224
- })],
235
+ }), w => !w.getRes(0)],
236
+ [w => Promise.resolve(false), w => w.getRes(0)],
225
237
  ])
226
238
  .then(result => {
227
239
  if (result) {
228
- debug(`still waiting for ${options.mode === this.WAIT_GONE ? 'gone' : 'presence'}: ${data}`);
229
- setTimeout(f, !presence ? 250 : 500);
240
+ debug(`still waiting ${target} to be ${options.mode === this.WAIT_GONE ? 'gone' : 'presence'}`);
241
+ setTimeout(f, 50);
230
242
  } else {
231
243
  resolve(el);
232
244
  }
233
245
  })
234
- .catch(err => reject(err));
246
+ .catch(err => {
247
+ if (err instanceof error.StaleElementReferenceError) {
248
+ debug(`stale on ${target}, resolving instead`);
249
+ resolve(el);
250
+ } else {
251
+ reject(err);
252
+ }
253
+ });
235
254
  }
236
255
  f();
237
256
  });
@@ -58,6 +58,7 @@ class SipdApp {
58
58
  By.xpath('//button[@type="submit"]')
59
59
  ), w => w.getRes(0).length],
60
60
  [w => this.waitCaptcha(), w => w.getRes(0).length],
61
+ [w => this.owner.waitForPresence({el: w.getRes(3), data: By.xpath('.//*[@class="indicator-progress"]')}, {mode: this.owner.WAIT_GONE}), w => w.getRes(0).length],
61
62
  [w => this.owner.sleep(this.owner.opdelay), w => w.getRes(0).length],
62
63
  ]);
63
64
  }
@@ -135,8 +136,6 @@ class SipdApp {
135
136
  w => w.getRes(0)],
136
137
  [w => this.owner.click(By.xpath('//ngx-captcha/div/div/input[@type="button"]')),
137
138
  w => w.getRes(0)],
138
- [w => this.owner.sleep(this.owner.opdelay),
139
- w => w.getRes(0)],
140
139
  [w => Promise.resolve(w.getRes(0))],
141
140
  ]);
142
141
  }
@@ -144,7 +143,7 @@ class SipdApp {
144
143
  waitSolvedCaptcha() {
145
144
  return this.owner.works([
146
145
  [w => Promise.resolve(this.owner.app.showMessage('Captcha', 'Please solve the captcha first!'))],
147
- [w => this.owner.waitForPresence(By.xpath('//ngx-captcha'))],
146
+ [w => this.owner.waitForPresence(By.xpath('//ngx-captcha'), {mode: this.owner.WAIT_GONE})],
148
147
  [w => Promise.resolve(console.log('Captcha is solved!'))],
149
148
  ]);
150
149
  }