How to use vmCtx method in Appium Base Driver

Best JavaScript code snippet using appium-base-driver

Run Appium Base Driver automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

index.js

Source: index.js Github

copy
1#!/usr/bin/env node
2
3const fs = require('fs');
4const path = require('path');
5const { promisify } = require('util');
6const vm = require('vm');
7
8const commonmark = require('commonmark');
9const cheerio = require('cheerio');
10
11// utils
12const readFile = promisify(fs.readFile);
13const writeFile = promisify(fs.writeFile);
14
15function parseContent(content) {
16	let readingKey = true;
17	let readingValue = false;
18	let key, value;
19	let mark = 0;
20	const parsed = {};
21	for (let i = 0; i < content.length; i++) {
22		switch (content[i]) {
23			case '=':
24				if (readingKey) {
25					readingKey = false;
26					key = content.substr(mark, i-mark);
27					mark = i+1;
28					readingValue = true;
29				}
30				break;
31			case '\n':
32				if (readingKey) {
33					parsed.content = content.substr(mark);
34					i = content.length;
35					break;
36				}
37				readingValue = false;
38				value = content.substr(mark, i-mark);
39
40				parsed[key] = value;
41				mark = i+1;
42				readingKey = true;
43				break;
44		}
45	}
46	var reader = new commonmark.Parser();
47	var writer = new commonmark.HtmlRenderer();
48	parsed.content = writer.render(reader.parse(parsed.content));
49	return parsed;
50}
51
52const contentCache = {};
53
54function contentFromFile(dirPath, relPath) {
55	const absPath = path.join(dirPath, relPath);
56	let parsed;
57	if (contentCache[absPath]) {
58		parsed = contentCache[absPath];
59	} else {
60		parsed = parseContent(fs.readFileSync(absPath, 'utf8'));
61		contentCache[absPath] = parsed;
62	}
63	const extIdx = relPath.lastIndexOf('.');
64	parsed.fileName = extIdx < 0 ? path.basename(relPath) : path.basename(relPath.substr(0, extIdx));
65	parsed.baseFileName = extIdx < 0 ? relPath : relPath.substr(0, extIdx);
66	parsed.relPath = relPath;
67	return parsed;
68}
69
70class Contents extends Array {
71	constructor() {
72		super(...arguments);
73	}
74
75	mostRecent(n=0, by='date') {
76		if (n <= 0 || n === undefined) {
77			n = this.length;
78		}
79		return this
80			.map(d => {
81				if (d[by]) {
82					return d;
83				}
84				d[by] = new Date() + "";
85				return d;
86			})
87			.sort((left, right) => {
88		        const ld = new Date(left[by]);
89		        const rd = new Date(right[by]);
90		        if (ld < rd) {
91		          return 1;
92		        } else if (ld > rd) {
93		          return -1;
94		        }
95		        return 0;
96		    })
97		    .slice(0, n);
98	}
99}
100
101function contentFromDirectory(baseDir, relPath) {
102	const dirPath = path.join(baseDir, relPath);
103	return new Contents(...fs.readdirSync(dirPath).map(filePath => {
104		return contentFromFile(baseDir, path.join(relPath, filePath));
105	}));
106}
107
108class Queue {
109	constructor() {
110		this.q = new Array();
111	}
112
113	enqueue(elem) {
114		this.q.unshift(elem);
115	}
116
117	dequeue() {
118		return this.q.pop();
119	}
120
121	isEmpty() {
122		return this.q.length === 0;
123	}
124}
125
126function mkdirRSync(mkpath) {
127	if (mkpath.length === 0) {
128		return;
129	}
130	const lof = mkpath.lastIndexOf(path.sep);
131	if (lof != -1) {
132		mkdirRSync(mkpath.substr(0, lof))
133	}
134	if (!fs.existsSync(mkpath)) {
135		fs.mkdirSync(mkpath);
136	}
137}
138
139class Compiler {
140	constructor(srcDir, vmCtx, compileQueue) {
141		this.srcDir = srcDir;
142		this.cwd = '';
143		this.vmCtx = vmCtx;
144		this.compileQueue = compileQueue;
145		this.cache = {};
146
147		// extend ctx
148		this.vmCtx.compile = this.compile.bind(this);
149		this.vmCtx.compileDyn = this.compileDyn.bind(this);
150		this.vmCtx.include = this.include.bind(this);
151	}
152
153	compileDyn(filePath) {
154		return this.compile(filePath, {dynamic: true})
155	}
156
157	include(includePath, opt) {
158		const filePath = path.join(this.srcDir, includePath);
159		const stat = fs.statSync(filePath);
160		if (stat.isDirectory()) {
161			const dirPath = filePath;
162			return fs.readdirSync(dirPath).filter(fileInDirPath => {
163				if (opt.excludeExt) {
164					let ext = fileInDirPath.startsWith(".") ? fileInDirPath : path.extname(fileInDirPath);
165					ext = ext.slice(1).toLowerCase();
166					const shouldInclude = opt.excludeExt.filter(excludeExt => {
167					  return excludeExt.toLowerCase() === ext;
168					}).length == 0;
169					return shouldInclude;
170				}
171				return true;
172			}).map(fileInDirPath => {
173				const filePath = path.join(includePath, fileInDirPath);
174				this.include(path.join(filePath));
175				return filePath;
176			}).flat();
177		}
178		this.compileQueue.enqueue([this.cwd, includePath]);
179		return includePath;
180	}
181
182	compile(filePath, opts={}) {
183		const absPath = path.join(this.cwd, filePath);
184		if (this.cache[absPath]) {
185			return this.cache[absPath];
186		}
187		let result;
188		switch (path.extname(filePath).toLowerCase()) {
189			case '.md': {
190				const content = contentFromFile(this.cwd, filePath);
191				if (!content.template) {
192					throw new Error("content missing template; cannot compile");
193				}
194				const templateFile = path.join(this.srcDir, content.template);
195				const data = cheerio.load(fs.readFileSync(templateFile, 'utf8'), {_useHtmlParser2: true});
196				const localCtx = vm.createContext({ ...this.vmCtx });
197				localCtx.content = content;
198				data('script[compile]').each((idx, s) => {
199					const result = vm.runInContext(`{${cheerio(s).html()}}`, localCtx);
200					cheerio(s).replaceWith(result);
201				});
202				filePath = content.out ?
203					path.join(path.dirname(filePath), content.out) :
204					filePath.substr(0, filePath.lastIndexOf('.')) + ".html";
205				result = [data.html(), filePath];
206				break;
207			};
208			case '.html': {
209				const data = cheerio.load(fs.readFileSync(absPath, 'utf8'), {_useHtmlParser2: true});
210				const localCtx = vm.createContext({ ...this.vmCtx });
211				localCtx.$ = data;
212				data('script[compile]').each((idx, s) => {
213					const result = vm.runInContext(`{${cheerio(s).html()}}`, localCtx);
214					cheerio(s).replaceWith(result);
215				});
216				data('a[compile-ref]').each((idx, t) => {
217					if (!this.compileQueue) {
218						return;
219					}
220					const ref = cheerio(t).attr('compile-ref');
221					cheerio(t).removeAttr('compile-ref');
222					if (!this.cache[path.join(this.cwd, ref)]) {
223						this.compileQueue.enqueue([this.cwd, ref]);						
224					}
225				})
226				data('link[compile-ref][rel="stylesheet"]').each((idx, t) => {
227					if (!this.compileQueue) {
228						return;
229					}
230					const ref = cheerio(t).attr('href');
231					cheerio(t).removeAttr('compile-ref');
232					if (!this.cache[path.join(this.cwd, ref)]) {
233						this.compileQueue.enqueue([this.cwd, ref]);						
234					}
235				})
236				data('img[compile-ref]').each((idx, t) => {
237					if (!this.compileQueue) {
238						return;
239					}
240					const src = cheerio(t).attr('src');
241					cheerio(t).removeAttr('compile-ref');
242					if (!this.cache[path.join(this.cwd, src)]) {
243						this.compileQueue.enqueue([this.cwd, src]);
244					}
245				})
246				result = data.html();
247				break;
248			};
249			case '.css':
250			case '.png':
251			case '.jpg': {
252				result = fs.readFileSync(absPath, 'binary');
253				break;
254			};
255			default:
256				throw new Error("do not know how to compile " + filePath);
257		}
258		if (!opts.dynamic) {
259			this.cache[absPath] = result;
260		}
261		return result;
262	}
263}
264
265// main
266(async () => {
267	if (!process.argv[2]) {
268		console.error("project directory required");
269		return;
270	}
271	const rootDir = process.argv[2];
272	const rootStat = fs.statSync(rootDir);
273	if (!rootStat.isDirectory()) {
274		console.error("project directory required");
275		return;
276	}
277
278	const configStr = await readFile(path.join(process.argv[2], 'config.json'), 'utf8')
279	const config = JSON.parse(configStr);
280	const srcDir = path.join(rootDir, 'src');
281
282	const ctx = {
283		'buildInfo': {
284			'date': new Date(),
285		},
286		'$': cheerio,
287		'content': from => {
288			const filePath = path.join(srcDir, from);
289			const stat = fs.statSync(filePath);
290			if (stat.isDirectory()) {
291				return contentFromDirectory(srcDir, from);
292			}
293			return contentFromFile(srcDir, from);
294		},
295		'console': console,
296		'config': config,
297		'tween': (arr, value) => {
298			const arrCopy = arr.slice();
299			const origLen = arrCopy.length;
300			const newLen = (origLen*2)-1;
301			for (let i = 0; i < newLen-1; i+=2) {
302				arrCopy.splice(i+1, 0, value);
303			}
304			return arrCopy;
305		}
306	};
307
308	try {
309		ctx.buildInfo.revision = require('child_process')
310			.execSync(`cd ${process.argv[2]}; git rev-parse --short HEAD`)
311			.toString().trim()
312	} catch (ignored) {}
313
314	vm.createContext(ctx);
315
316	const indexRelPath = config.src || "index.html";
317
318	const compileQueue = new Queue();
319	compileQueue.enqueue([srcDir, indexRelPath]);
320	const compiler = new Compiler(srcDir, ctx, compileQueue);
321
322	while (!compileQueue.isEmpty()) {
323		let [baseDir, relPath] = compileQueue.dequeue();
324		compiler.cwd = baseDir;
325		try {
326			ctx.path = path.join('/', relPath);
327			let file = compiler.compile(relPath);
328			if (config.out) {
329				const outDir = path.join(rootDir, config.out);
330				if (file instanceof Array) {
331					relPath = file[1];
332					file = file[0];
333				}
334				const outPath = path.join(outDir, relPath);
335				mkdirRSync(path.dirname(outPath));
336				await writeFile(outPath, file, {encoding: 'binary'})
337				console.info("updated", outPath);
338			}
339		} catch (err) {
340			console.error("error compiling", err)
341			process.exit(1);
342		}
343	}
344})();
345
Full Screen

main.js

Source: main.js Github

copy
1function googleSuccess() {
2  'use strict';
3  console.log('m here');
4  // List of markers to display on map
5  var markers = [
6    {
7      placeName: 'San Francisco Zoo',
8      icon: 'img/koala.png',
9      latLng: {
10        lat: 37.732873,
11        lng: -122.502972
12      },
13      photos: [
14        'img/sf-zoo-1.jpg',
15        'img/sf-zoo-2.jpg',
16        'img/sf-zoo-3.jpg'
17      ]
18    },
19    {
20      placeName: 'Mission Dolores Park',
21      icon: 'img/park.png',
22      latLng: {
23        lat: 37.759718,
24        lng: -122.427058
25      },
26      photos: [
27        'img/dolores-park-1.jpg',
28        'img/dolores-park-2.jpg',
29        'img/dolores-park-3.jpg'
30      ]
31    },
32    {
33      placeName: 'Japanese Tea Garden',
34      icon: 'img/garden.png',
35      latLng: {
36        lat: 37.769752,
37        lng: -122.469799
38      },
39      photos: [
40        'img/japanese-garden-1.jpg',
41        'img/japanese-garden-2.jpg',
42        'img/japanese-garden-3.jpg'
43      ]
44    },
45    {
46      placeName: 'Baker Beach',
47      icon: 'img/beach.png',
48      latLng: {
49        lat: 37.793562,
50        lng: -122.483578
51      },
52      photos: [
53        'img/baker-beach-1.jpg',
54        'img/baker-beach-2.jpg',
55        'img/baker-beach-3.jpg'
56      ]
57    },
58    {
59      placeName: 'Fort Point',
60      icon: 'img/fort.png',
61      latLng: {
62        lat: 37.810594,
63        lng: -122.476964
64      },
65      photos: [
66        'img/fort-point-1.jpg',
67        'img/fort-point-2.jpg',
68        'img/fort-point-3.jpg'
69      ]
70    },
71    {
72      placeName: 'Coit Tower',
73      icon: 'img/tower.png',
74      latLng: {
75        lat: 37.802396,
76        lng: -122.405789
77      },
78      photos: [
79        'img/coit-tower-1.jpg',
80        'img/coit-tower-2.jpg',
81        'img/coit-tower-3.jpg'
82      ]
83    }
84  ];
85
86  /**
87   * Helper function to check if element has certain class
88   */
89  function hasClass(element, className) {
90    return (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1;
91  }
92
93  /**
94   * Represents a single map marker
95   */
96  var Marker = function (latLng, placeName, icon, map) {
97    return new google.maps.Marker({
98      position: latLng,
99      map: map,
100      icon: icon,
101      title: placeName
102    });
103  };
104
105  /**
106   * Append a button to the infowindow for the random yes or no answer
107   */
108  var appendYesOrNo = function(marker) {
109    // Get the info window currently displayed.
110    var infowindow = document.getElementById('info');
111    // Attach a button to call YesOrNo API
112    var div = document.createElement('div');
113    div.id = 'answer';
114    var btn = document.createElement('button');
115    btn.id = 'questionBtn';
116    var t = document.createTextNode('Do you think I should go?');
117    btn.appendChild(t);
118    btn.onclick = (function(){return yesOrNo(marker)});
119    div.appendChild(btn);
120    infowindow.appendChild(div);
121  };
122
123  /**
124   * Use yesno api to retrieve a random yes or no answer with a gif
125   */
126  var yesOrNo = function(marker) {
127    var xhttp = new XMLHttpRequest();
128    var yesOrNoApiUrl = 'http://yesno.wtf/api/'
129    xhttp.onreadystatechange = function() {
130      if (xhttp.readyState == 4 && xhttp.status == 200) {
131        var responseJson = JSON.parse(xhttp.responseText);
132        var oImg=document.createElement('img');
133        var btn = document.getElementById('questionBtn');
134        oImg.setAttribute('src', responseJson.image);
135        btn.style.display = 'none';
136        document.getElementById('answer').appendChild(oImg);
137
138        // Change center of map for marker to be at the bottom,
139        // to display full info window
140        var map = marker.getMap();
141        var markerPos = marker.getPosition();
142        var getSouthWest = map.getBounds().getSouthWest();
143        var mapCenter = map.getCenter();
144
145        var markerPosSWDiff = markerPos.lat() - getSouthWest.lat();
146
147        var newLat = mapCenter.lat() + (markerPosSWDiff/2);
148
149        map.setCenter({lat: newLat, lng: mapCenter.lng()});
150      } else if (xhttp.readyState == 4 && xhttp.status != 200) {
151        document.getElementById('error').innerHTML = 'Something went wrong. Ask me later!';
152      }
153    };
154    xhttp.open('GET', yesOrNoApiUrl, true);
155    xhttp.send();
156  };
157
158  /**
159   * Use Foursquare api to get the place id then use it to get tips
160   */
161  function getFoursquareTips(marker) {
162      var xhttp = new XMLHttpRequest();
163      var getPlaceUrl = 'https://api.foursquare.com/v2/venues/search?'+
164        'll=' + marker.position.lat() + ',' + marker.position.lng() +
165        '&limit=1&radius=100&'+
166        'oauth_token=MA1GR4J2VETXZPIGSPCMSS1A4WGKLVFFG41IVZMQY54KXIP2&'+
167        'v=20140806';
168      xhttp.onreadystatechange = function() {
169        if (xhttp.readyState == 4 && xhttp.status == 200) {
170          var responseJson = JSON.parse(xhttp.responseText);
171          getTips(responseJson.response.venues[0].id);
172        } else if (xhttp.readyState == 4 && xhttp.status != 200) {
173          document.getElementById('error').innerHTML = 'Sorry. We\'re unable to find info about the place!';
174        }
175      };
176      xhttp.open('GET', getPlaceUrl, true);
177      xhttp.send();
178    };
179
180    /**
181     * Use Foursquare api to get tips for the place giving the place id
182     */
183    function getTips(placeId) {
184      var xhttp = new XMLHttpRequest();
185      var getTipsUrl = 'https://api.foursquare.com/v2/venues/'+
186        placeId + '/tips?'+
187        'oauth_token=MA1GR4J2VETXZPIGSPCMSS1A4WGKLVFFG41IVZMQY54KXIP2&v=20140806'+
188        '&sort=popular&limit=3';
189      xhttp.onreadystatechange = function() {
190        if (xhttp.readyState == 4 && xhttp.status == 200) {
191          var responseJson = JSON.parse(xhttp.responseText);
192          var text = document.createTextNode(responseJson.response.tips.items[0].text);
193
194          var tipsDiv = document.getElementById('tips');
195          tipsDiv.appendChild(text);
196        } else if (xhttp.readyState == 4 && xhttp.status != 200) {
197          document.getElementById('error').innerHTML = 'Sorry. We\'re unable to find any tips!';
198        }
199      };
200      xhttp.open('GET', getTipsUrl, true);
201      xhttp.send();
202    };
203
204  /**
205   * The ViewModel for our neighborhood App
206   */
207  var ViewModel = function (markers) {
208    // Refer to the context of ViewModel
209    var vmCtx = this;
210    this.currentPlaceImages = ko.observableArray([]);
211
212    // Define center of map and map options
213    var myLatlng = new google.maps.LatLng(37.765733, -122.454162);
214    var mapOptions = {
215      zoom: 12,
216      center: myLatlng,
217      mapTypeId: google.maps.MapTypeId.ROADMAP
218    };
219
220    // Load map in map div
221    this.map = new google.maps.Map(document.getElementById('map'),
222      mapOptions);
223
224    // Create one infowindow to be used by all marker, instead of creating one
225    // for every marker, to avoid visual clutter and have only one window open
226    // at any given time
227    this.infowindow = new google.maps.InfoWindow();
228
229    /**
230     * Executes when a marker or its corresponding name in the list is clicked
231     */
232    this.highlightMarker = function(marker) {
233      var self = vmCtx;
234
235      // Check if name list is shown, hide it.
236      // This hides the fullscreen list of places names when it's on mobile
237      var nameList = document.getElementById('list-menu');
238      if(hasClass(nameList, 'activated')) {
239        nameList.className = '';
240      }
241      var content = '<div id="info"><h1>' + marker.title + '</h1>'+
242        '<div id="tips"></div><div id="error"></div>'+'</div>';
243      vmCtx.infowindow.setContent(content);
244      vmCtx.infowindow.open(marker.get('map'), marker);
245      vmCtx.map.setZoom(12);
246      vmCtx.pounceMarker(marker);
247      vmCtx.addPhotos(marker);
248      getFoursquareTips(marker);
249      appendYesOrNo(marker);
250    };
251
252    /**
253     * Triggers marker pounce animation
254     */
255    this.pounceMarker = function(marker) {
256      // Trigger animation
257      marker.setAnimation(google.maps.Animation.BOUNCE);
258      // Stop animation
259      vmCtx.stopAnimation(marker);
260      // Set center of map to the current marker position
261      vmCtx.map.panTo(marker.getPosition());
262    };
263
264    /**
265     * Stop marker pounce animation
266     */
267    this.stopAnimation = function(marker) {
268      setTimeout(function () {
269          marker.setAnimation(null);
270      }, 1000);
271    };
272
273    /**
274     * Add current marker's place photos to currentPlaceImages observable array
275     */
276    this.addPhotos = function(marker) {
277      var len = marker.photos.length,
278        photos = marker.photos;
279      // Clear pictures of past marker
280      vmCtx.currentPlaceImages.removeAll();
281
282      // Add the new marker photos
283      for(var i = 0; i < len; ++i) {
284        vmCtx.currentPlaceImages.push(photos[i]);
285      }
286    };
287
288    /**
289     * Map array of passed markers to an observableArray of Marker objects
290     */
291    this.markers = ko.observableArray(markers.map(function (marker) {
292      var photos = marker.photos;
293      var marker = new Marker(marker.latLng, marker.placeName, marker.icon, vmCtx.map);
294      marker.photos = photos;
295      google.maps.event.addListener(marker, 'click', function() {
296        vmCtx.highlightMarker(marker);
297      });
298      return marker;
299    }));
300
301    // Keep track of visible markers
302    this.visibleMarkers = this.markers;
303
304    // Show List of names
305    this.activateList = function() {
306      var element = document.getElementById('list-menu');
307      console.log(element.style);
308      if(!element.style.display) {
309        element.className = 'activated';
310      }
311    }
312
313    // Value of search query
314    this.query = ko.observable('');
315
316    /**
317     * Search markers for a name that matches the search query and
318     * add the matched markers to the visibleMarkers observable array
319     */
320    this.runQuery = ko.computed(function() {
321      this.visibleMarkers = ko.computed(function() {
322        var query = this.query()
323        // Filter array elements based on place name, hide the markers that are not a match
324        // and save results in visibleMarkers observable array
325        return this.markers().filter(function (marker) {
326          if(marker.title.toLowerCase().indexOf(query.toLowerCase()) >= 0) {
327            marker.setVisible(true);
328            return marker;
329          } else {
330            marker.setVisible(false);
331          }
332        });
333      }, this);
334    }, this);
335  };
336
337  // Bind a new instance of our view model to the page
338  var viewModel = new ViewModel(markers || []);
339  ko.applyBindings(viewModel);
340  console.log(viewModel);
341}
342
343function googleError(){
344  var app = document.getElementById('app');
345  app.innerHTML = '<div class="error">'+ '<p>Unfortunately we\'re unable to load the map. '+
346    'Here\'s some cute cats instead! </p>' +
347    '<img src="img/cutecat.jpg"></div>';
348}
349
Full Screen

script-searcher.js

Source: script-searcher.js Github

copy
1'use strict';
2
3const vm = require('vm');
4const DEBUG = true;
5
6const getScriptUrl = function(embededPage) {
7	if (typeof embededPage !== 'string') throw new Error('Invalid argument: argument must be type of "string"');
8	const match = Array.from(embededPage.matchAll(/<script\s+src\s*=\s*"(?<path>[[email protected]:%._\/\+~#=]+)\/base.js"/g));
9	if (match.length === 0) throw new Error('Script */base.js does not exists');
10	return match[0].groups.path + '/base.js';
11};
12
13const Searcher = function(script) {
14	const _getDecipherCode = function() {
15		/*
16			source from youtube-dl: _parse_sig_js(self, jscode);
17		*/
18		const commonPtrn = [
19			/\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?<funcName>[a-zA-Z0-9$]+)\(/,
20	        /\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?<funcName>[a-zA-Z0-9$]+)\(/,
21	        /(?:\b|[^a-zA-Z0-9$])(?<funcName>[a-zA-Z0-9$]{2})\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)/,
22	        /(?<funcName>[a-zA-Z0-9$]+)\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)/
23		];
24		let entryFunc = null;
25		commonPtrn.some((r) => {
26			const match = script.match(r);
27			if (!match) return false;
28			entryFunc = match.groups.funcName;
29			return true
30		})
31		if (!entryFunc) throw new Error('Cannot find entry function for decryption');
32		const entryFuncCode = _getVarDefinition(entryFunc);
33		printLog(`varName: ${entryFunc}, def: ${entryFuncCode}`);
34		let funcList = [entryFuncCode];
35		let maxAllowedTry = 100;
36		let vmCtx = {};
37		vm.createContext(vmCtx);
38		vm.runInContext(entryFuncCode, vmCtx);
39		do {
40			try {
41				--maxAllowedTry;
42				printLog('eval entry function: ' + maxAllowedTry);
43				vm.runInContext(`${entryFunc}('_dummy_string_')`, vmCtx);
44				break;
45			} catch (e) {
46				if (e.name === 'ReferenceError') {
47					const fname = _getUndefinedVarName(e.message);
48					const fcode = _getVarDefinition(fname);
49					printLog(`varName: ${fname}, def: ${fcode}`);
50					vm.runInContext(fcode, vmCtx);
51					funcList.push(fcode);
52				} else {
53					printLog(`Unknown error: ${e}`);
54					throw e;
55				}
56			}
57		} while (maxAllowedTry > 0)
58		if (maxAllowedTry === 0) throw new Error('Cannot obtain decrypt function within 100 tries');
59		return {
60			entry: entryFunc,
61			code: funcList.join('\n')
62		};
63	}
64	const _getUndefinedVarName = function(errMsg) {
65		printLog(`getUndefinedVarName: ${errMsg}`)
66		const match = errMsg.match(/^(?<varName>\w+) is not defined$/);
67		if (!match) throw new Error(`Unexpected error: ${errMsg}`);
68		else printLog(match.groups.varName);
69		return match.groups.varName;
70	}
71	const _getVarDefinition = function(varName) {
72		// accept var definition in following style:
73		// (var|let|const|) varName=(*|function(*))
74		// special checking: varName cannot follow any character other than [,;\s]
75		// assume var definition ends with ';' and no string literals included
76		const dec = script.match(new RegExp(`(?:\\b(?:var|let|const)\\s+)?(?:[,;\\s]+|^)${varName}\\s*=\\s*(?<f>function\\s*\\([^)]*\\))?`));
77		if (!dec) throw new Error(`Cannot find variable ${varName}`);
78		const sIdx = dec.index + dec[0].length;
79		let eIdx = 0;
80		if (!dec.groups.f) {
81			// non-function definition
82			let c = script[sIdx];
83			if (c === '{' || c === '[' || c === '(') {
84				eIdx = _balanceSymbol(sIdx);
85			} else {
86				eIdx = sIdx;
87				do {
88					c = script[++eIdx];
89				}
90				while (c !== ';')
91			}
92		} else {
93			// function definition
94			eIdx = _balanceSymbol(sIdx);
95		}
96		return dec[0] + script.substring(sIdx, eIdx);
97	}
98	const _balanceSymbol = function(startIdx) {
99		// find end index of symbol that balances code starts with start index
100		// assume no string literals in code
101		let idx = startIdx;
102		let stack = [];
103		while (idx < script.length) {
104			const c = script[idx];
105			++idx;
106			switch (c) {
107				case '{':
108				case '(':
109				case '[':
110					stack.push(c);
111					break;
112				case '}':
113					if (stack.length > 0 && stack[stack.length-1] === '{') {
114						stack.pop();
115					} else throw new Error('Inbalanced bracket "}"');
116					break;
117				case ')':
118					if (stack.length > 0 && stack[stack.length-1] === '(') {
119						stack.pop();
120					} else throw new Error('Inbalanced bracket ")"');
121					break;
122				case ']':
123					if (stack.length > 0 && stack[stack.length-1] === '[') {
124						stack.pop();
125					} else throw new Error('Inbalanced bracket "]"');
126					break;
127			}
128			if (stack.length === 0) break;
129		}
130		if (stack.length !== 0) throw new Error('Inbalanced brackets');
131		return idx;
132	}
133	this.decipherCode = _getDecipherCode();
134};
135
136const Decrypter = function(decipherCode) {
137	let vmCtx = {};
138	vm.createContext(vmCtx);
139	vm.runInContext(decipherCode.code, vmCtx);
140	const decipher = vm.runInContext(decipherCode.entry, vmCtx);
141	this.getDecryptedUrl = function(cipher) {
142		// cipher contains 3 url parameters: s(encrypted signature), sp(param to be added to result url), url
143		const params = cipher.split('&');
144		let paramMap = {};
145		params.forEach((pair) => {
146			let kV = pair.split('=');
147			if (kV.length == 2) {
148				paramMap[kV[0]] = kV[1];
149			}
150		});
151		if (!paramMap.s) throw new Error('Missing "s" parameter in signatureCipher');
152		if (!paramMap.sp) throw new Error('Missing "sp" parameter in signatureCipher');
153		if (!paramMap.url) throw new Error('Missing "url" parameter in signatureCipher');
154		const signature = decipher(decodeURIComponent(paramMap.s));
155		return decodeURIComponent(paramMap.url) + '&' + paramMap.sp + '=' + signature +
156			'&ratebypass=yes';
157	};
158};
159
160const printLog = function(message) {
161	if (DEBUG) console.log(message);
162}
163
164module.exports = { getScriptUrl, Searcher, Decrypter };
165
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Appium Base Driver on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)