appium-safari-driver 2.2.0 → 3.0.4
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/.eslintrc +1 -1
- package/.github/workflows/publish.js.yml +30 -0
- package/.releaserc +12 -0
- package/LICENSE +201 -0
- package/README.md +13 -5
- package/build/index.js +9 -6
- package/build/lib/commands/cookies.js +21 -0
- package/build/lib/commands/find.js +3 -3
- package/build/lib/commands/index.js +6 -2
- package/build/lib/commands/record-screen.js +329 -0
- package/build/lib/driver.js +9 -5
- package/build/lib/logger.js +3 -3
- package/build/lib/safari.js +10 -10
- package/build/lib/server.js +4 -4
- package/build/test/functional/desktop-driver-e2e-specs.js +11 -8
- package/build/test/functional/mobile-driver-e2e-specs.js +11 -8
- package/build/test/utils.js +1 -1
- package/gulpfile.js +3 -2
- package/index.js +6 -3
- package/lib/commands/cookies.js +8 -0
- package/lib/commands/find.js +1 -1
- package/lib/commands/index.js +4 -0
- package/lib/commands/record-screen.js +310 -0
- package/lib/driver.js +6 -2
- package/lib/logger.js +1 -1
- package/lib/safari.js +2 -2
- package/lib/server.js +3 -1
- package/npm-shrinkwrap.json +2180 -0
- package/package.json +19 -12
- package/test/functional/desktop-driver-e2e-specs.js +10 -7
- package/test/functional/mobile-driver-e2e-specs.js +10 -7
|
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
|
|
5
5
|
require("source-map-support/register");
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _webdriverio = require("webdriverio");
|
|
8
8
|
|
|
9
9
|
var _ = require("../..");
|
|
10
10
|
|
|
@@ -36,21 +36,24 @@ describe('Desktop SafariDriver', function () {
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
beforeEach(async function () {
|
|
39
|
-
driver =
|
|
40
|
-
|
|
39
|
+
driver = await (0, _webdriverio.remote)({
|
|
40
|
+
hostname: _utils.HOST,
|
|
41
|
+
port: _utils.PORT,
|
|
42
|
+
capabilities: CAPS
|
|
43
|
+
});
|
|
41
44
|
});
|
|
42
45
|
afterEach(async function () {
|
|
43
46
|
if (driver) {
|
|
44
|
-
await driver.
|
|
47
|
+
await driver.deleteSession();
|
|
45
48
|
driver = null;
|
|
46
49
|
}
|
|
47
50
|
});
|
|
48
51
|
it('should start and stop a session', async function () {
|
|
49
|
-
await driver.
|
|
50
|
-
const button = await driver
|
|
51
|
-
await button.
|
|
52
|
+
await driver.url('https://appium.io/');
|
|
53
|
+
const button = await driver.$('#downloadLink');
|
|
54
|
+
await button.getText().should.eventually.eql('Download Appium');
|
|
52
55
|
});
|
|
53
56
|
});require('source-map-support').install();
|
|
54
57
|
|
|
55
58
|
|
|
56
|
-
//# sourceMappingURL=data:application/json;charset=utf8;base64,
|
|
59
|
+
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZnVuY3Rpb25hbC9kZXNrdG9wLWRyaXZlci1lMmUtc3BlY3MuanMiXSwibmFtZXMiOlsiY2hhaSIsInNob3VsZCIsInVzZSIsImNoYWlBc1Byb21pc2VkIiwiQ0FQUyIsImJyb3dzZXJOYW1lIiwicGxhdGZvcm1OYW1lIiwiZGVzY3JpYmUiLCJ0aW1lb3V0IiwiTU9DSEFfVElNRU9VVCIsInNlcnZlciIsImRyaXZlciIsImJlZm9yZSIsIlBPUlQiLCJIT1NUIiwiYWZ0ZXIiLCJjbG9zZSIsImJlZm9yZUVhY2giLCJob3N0bmFtZSIsInBvcnQiLCJjYXBhYmlsaXRpZXMiLCJhZnRlckVhY2giLCJkZWxldGVTZXNzaW9uIiwiaXQiLCJ1cmwiLCJidXR0b24iLCIkIiwiZ2V0VGV4dCIsImV2ZW50dWFsbHkiLCJlcWwiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUVBQSxjQUFLQyxNQUFMOztBQUNBRCxjQUFLRSxHQUFMLENBQVNDLHVCQUFUOztBQUdBLE1BQU1DLElBQUksR0FBRztBQUNYQyxFQUFBQSxXQUFXLEVBQUUsY0FERjtBQUVYQyxFQUFBQSxZQUFZLEVBQUU7QUFGSCxDQUFiO0FBS0FDLFFBQVEsQ0FBQyxzQkFBRCxFQUF5QixZQUFZO0FBQzNDLE9BQUtDLE9BQUwsQ0FBYUMsb0JBQWI7QUFFQSxNQUFJQyxNQUFKO0FBQ0EsTUFBSUMsTUFBSjtBQUNBQyxFQUFBQSxNQUFNLENBQUMsa0JBQWtCO0FBQ3ZCRixJQUFBQSxNQUFNLEdBQUcsTUFBTSxtQkFBWUcsV0FBWixFQUFrQkMsV0FBbEIsQ0FBZjtBQUNELEdBRkssQ0FBTjtBQUdBQyxFQUFBQSxLQUFLLENBQUMsa0JBQWtCO0FBQ3RCLFFBQUlMLE1BQUosRUFBWTtBQUNWLFlBQU1BLE1BQU0sQ0FBQ00sS0FBUCxFQUFOO0FBQ0FOLE1BQUFBLE1BQU0sR0FBRyxJQUFUO0FBQ0Q7QUFDRixHQUxJLENBQUw7QUFNQU8sRUFBQUEsVUFBVSxDQUFDLGtCQUFrQjtBQUMzQk4sSUFBQUEsTUFBTSxHQUFHLE1BQU0seUJBQU87QUFDcEJPLE1BQUFBLFFBQVEsRUFBRUosV0FEVTtBQUVwQkssTUFBQUEsSUFBSSxFQUFFTixXQUZjO0FBR3BCTyxNQUFBQSxZQUFZLEVBQUVoQjtBQUhNLEtBQVAsQ0FBZjtBQUtELEdBTlMsQ0FBVjtBQU9BaUIsRUFBQUEsU0FBUyxDQUFDLGtCQUFrQjtBQUMxQixRQUFJVixNQUFKLEVBQVk7QUFDVixZQUFNQSxNQUFNLENBQUNXLGFBQVAsRUFBTjtBQUNBWCxNQUFBQSxNQUFNLEdBQUcsSUFBVDtBQUNEO0FBQ0YsR0FMUSxDQUFUO0FBT0FZLEVBQUFBLEVBQUUsQ0FBQyxpQ0FBRCxFQUFvQyxrQkFBa0I7QUFDdEQsVUFBTVosTUFBTSxDQUFDYSxHQUFQLENBQVcsb0JBQVgsQ0FBTjtBQUNBLFVBQU1DLE1BQU0sR0FBRyxNQUFNZCxNQUFNLENBQUNlLENBQVAsQ0FBUyxlQUFULENBQXJCO0FBQ0EsVUFBTUQsTUFBTSxDQUFDRSxPQUFQLEdBQWlCMUIsTUFBakIsQ0FBd0IyQixVQUF4QixDQUFtQ0MsR0FBbkMsQ0FBdUMsaUJBQXZDLENBQU47QUFDRCxHQUpDLENBQUY7QUFLRCxDQWpDTyxDQUFSIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmVtb3RlIH0gZnJvbSAnd2ViZHJpdmVyaW8nO1xuaW1wb3J0IHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuLi8uLic7XG5pbXBvcnQgY2hhaUFzUHJvbWlzZWQgZnJvbSAnY2hhaS1hcy1wcm9taXNlZCc7XG5pbXBvcnQgY2hhaSBmcm9tICdjaGFpJztcbmltcG9ydCB7IEhPU1QsIFBPUlQsIE1PQ0hBX1RJTUVPVVQgfSBmcm9tICcuLi91dGlscyc7XG5cbmNoYWkuc2hvdWxkKCk7XG5jaGFpLnVzZShjaGFpQXNQcm9taXNlZCk7XG5cblxuY29uc3QgQ0FQUyA9IHtcbiAgYnJvd3Nlck5hbWU6ICdBcHBpdW1TYWZhcmknLFxuICBwbGF0Zm9ybU5hbWU6ICdtYWMnLFxufTtcblxuZGVzY3JpYmUoJ0Rlc2t0b3AgU2FmYXJpRHJpdmVyJywgZnVuY3Rpb24gKCkge1xuICB0aGlzLnRpbWVvdXQoTU9DSEFfVElNRU9VVCk7XG5cbiAgbGV0IHNlcnZlcjtcbiAgbGV0IGRyaXZlcjtcbiAgYmVmb3JlKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBzZXJ2ZXIgPSBhd2FpdCBzdGFydFNlcnZlcihQT1JULCBIT1NUKTtcbiAgfSk7XG4gIGFmdGVyKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoc2VydmVyKSB7XG4gICAgICBhd2FpdCBzZXJ2ZXIuY2xvc2UoKTtcbiAgICAgIHNlcnZlciA9IG51bGw7XG4gICAgfVxuICB9KTtcbiAgYmVmb3JlRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgZHJpdmVyID0gYXdhaXQgcmVtb3RlKHtcbiAgICAgIGhvc3RuYW1lOiBIT1NULFxuICAgICAgcG9ydDogUE9SVCxcbiAgICAgIGNhcGFiaWxpdGllczogQ0FQUyxcbiAgICB9KTtcbiAgfSk7XG4gIGFmdGVyRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKGRyaXZlcikge1xuICAgICAgYXdhaXQgZHJpdmVyLmRlbGV0ZVNlc3Npb24oKTtcbiAgICAgIGRyaXZlciA9IG51bGw7XG4gICAgfVxuICB9KTtcblxuICBpdCgnc2hvdWxkIHN0YXJ0IGFuZCBzdG9wIGEgc2Vzc2lvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBhd2FpdCBkcml2ZXIudXJsKCdodHRwczovL2FwcGl1bS5pby8nKTtcbiAgICBjb25zdCBidXR0b24gPSBhd2FpdCBkcml2ZXIuJCgnI2Rvd25sb2FkTGluaycpO1xuICAgIGF3YWl0IGJ1dHRvbi5nZXRUZXh0KCkuc2hvdWxkLmV2ZW50dWFsbHkuZXFsKCdEb3dubG9hZCBBcHBpdW0nKTtcbiAgfSk7XG59KTtcblxuXG4iXSwiZmlsZSI6InRlc3QvZnVuY3Rpb25hbC9kZXNrdG9wLWRyaXZlci1lMmUtc3BlY3MuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vLi4ifQ==
|
|
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
|
|
5
5
|
require("source-map-support/register");
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _webdriverio = require("webdriverio");
|
|
8
8
|
|
|
9
9
|
var _ = require("../..");
|
|
10
10
|
|
|
@@ -63,21 +63,24 @@ describe('Mobile SafariDriver', function () {
|
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
beforeEach(async function () {
|
|
66
|
-
driver =
|
|
67
|
-
|
|
66
|
+
driver = await (0, _webdriverio.remote)({
|
|
67
|
+
hostname: _utils.HOST,
|
|
68
|
+
port: _utils.PORT,
|
|
69
|
+
capabilities: CAPS
|
|
70
|
+
});
|
|
68
71
|
});
|
|
69
72
|
afterEach(async function () {
|
|
70
73
|
if (driver) {
|
|
71
|
-
await driver.
|
|
74
|
+
await driver.deleteSession();
|
|
72
75
|
driver = null;
|
|
73
76
|
}
|
|
74
77
|
});
|
|
75
78
|
it('should start and stop a session', async function () {
|
|
76
|
-
await driver.
|
|
77
|
-
const button = await driver
|
|
78
|
-
await button.
|
|
79
|
+
await driver.url('https://appium.io/');
|
|
80
|
+
const button = await driver.$('#downloadLink');
|
|
81
|
+
await button.getText().should.eventually.eql('Download Appium');
|
|
79
82
|
});
|
|
80
83
|
});require('source-map-support').install();
|
|
81
84
|
|
|
82
85
|
|
|
83
|
-
//# sourceMappingURL=data:application/json;charset=utf8;base64,
|
|
86
|
+
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZnVuY3Rpb25hbC9tb2JpbGUtZHJpdmVyLWUyZS1zcGVjcy5qcyJdLCJuYW1lcyI6WyJjaGFpIiwic2hvdWxkIiwidXNlIiwiY2hhaUFzUHJvbWlzZWQiLCJQTEFURk9STV9WRVJTSU9OIiwicHJvY2VzcyIsImVudiIsIkRFVklDRV9OQU1FIiwiQ0FQUyIsImJyb3dzZXJOYW1lIiwicGxhdGZvcm1OYW1lIiwiZGVzY3JpYmUiLCJ0aW1lb3V0IiwiTU9DSEFfVElNRU9VVCIsInNlcnZlciIsImRyaXZlciIsImJlZm9yZSIsIkNJIiwic2tpcCIsInNpbWN0bCIsIlNpbWN0bCIsImFsbERldmljZXMiLCJnZXREZXZpY2VzIiwiZGV2aWNlIiwiZmluZCIsIm5hbWUiLCJFcnJvciIsInN0YXRlIiwidWRpZCIsImJvb3REZXZpY2UiLCJzdGFydEJvb3RNb25pdG9yIiwiUE9SVCIsIkhPU1QiLCJhZnRlciIsImNsb3NlIiwiYmVmb3JlRWFjaCIsImhvc3RuYW1lIiwicG9ydCIsImNhcGFiaWxpdGllcyIsImFmdGVyRWFjaCIsImRlbGV0ZVNlc3Npb24iLCJpdCIsInVybCIsImJ1dHRvbiIsIiQiLCJnZXRUZXh0IiwiZXZlbnR1YWxseSIsImVxbCJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBRUFBLGNBQUtDLE1BQUw7O0FBQ0FELGNBQUtFLEdBQUwsQ0FBU0MsdUJBQVQ7O0FBRUEsTUFBTUMsZ0JBQWdCLEdBQUdDLE9BQU8sQ0FBQ0MsR0FBUixDQUFZRixnQkFBWixJQUFnQyxNQUF6RDtBQUNBLE1BQU1HLFdBQVcsR0FBR0YsT0FBTyxDQUFDQyxHQUFSLENBQVlDLFdBQVosSUFBMkIsbUJBQS9DO0FBQ0EsTUFBTUMsSUFBSSxHQUFHO0FBQ1hDLEVBQUFBLFdBQVcsRUFBRSxjQURGO0FBRVhDLEVBQUFBLFlBQVksRUFBRSxLQUZIO0FBR1gseUJBQXVCLElBSFo7QUFJWCw0QkFBMEJOLGdCQUpmO0FBS1gsdUJBQXFCRztBQUxWLENBQWI7QUFRQUksUUFBUSxDQUFDLHFCQUFELEVBQXdCLFlBQVk7QUFDMUMsT0FBS0MsT0FBTCxDQUFhQyxvQkFBYjtBQUVBLE1BQUlDLE1BQUo7QUFDQSxNQUFJQyxNQUFKO0FBQ0FDLEVBQUFBLE1BQU0sQ0FBQyxrQkFBa0I7QUFDdkIsUUFBSVgsT0FBTyxDQUFDQyxHQUFSLENBQVlXLEVBQWhCLEVBQW9CO0FBSWxCLGFBQU8sS0FBS0MsSUFBTCxFQUFQO0FBQ0Q7O0FBR0QsVUFBTUMsTUFBTSxHQUFHLElBQUlDLG1CQUFKLEVBQWY7QUFDQSxVQUFNQyxVQUFVLEdBQUcsTUFBTUYsTUFBTSxDQUFDRyxVQUFQLENBQWtCbEIsZ0JBQWxCLEVBQW9DLEtBQXBDLENBQXpCO0FBQ0EsVUFBTW1CLE1BQU0sR0FBR0YsVUFBVSxDQUFDRyxJQUFYLENBQWdCLENBQUM7QUFBQ0MsTUFBQUE7QUFBRCxLQUFELEtBQVlBLElBQUksS0FBS2xCLFdBQXJDLENBQWY7O0FBQ0EsUUFBSSxDQUFDZ0IsTUFBTCxFQUFhO0FBQ1gsWUFBTSxJQUFJRyxLQUFKLENBQVcsZ0JBQWVuQixXQUFZLGdCQUFlSCxnQkFBaUIsR0FBdEUsQ0FBTjtBQUNEOztBQUNELFFBQUltQixNQUFNLENBQUNJLEtBQVAsS0FBaUIsUUFBckIsRUFBK0I7QUFDN0JSLE1BQUFBLE1BQU0sQ0FBQ1MsSUFBUCxHQUFjTCxNQUFNLENBQUNLLElBQXJCO0FBQ0EsWUFBTVQsTUFBTSxDQUFDVSxVQUFQLEVBQU47QUFDQSxZQUFNVixNQUFNLENBQUNXLGdCQUFQLEVBQU47QUFDRDs7QUFFRGhCLElBQUFBLE1BQU0sR0FBRyxNQUFNLG1CQUFZaUIsV0FBWixFQUFrQkMsV0FBbEIsQ0FBZjtBQUNELEdBdEJLLENBQU47QUF1QkFDLEVBQUFBLEtBQUssQ0FBQyxrQkFBa0I7QUFDdEIsUUFBSW5CLE1BQUosRUFBWTtBQUNWLFlBQU1BLE1BQU0sQ0FBQ29CLEtBQVAsRUFBTjtBQUNBcEIsTUFBQUEsTUFBTSxHQUFHLElBQVQ7QUFDRDtBQUNGLEdBTEksQ0FBTDtBQU1BcUIsRUFBQUEsVUFBVSxDQUFDLGtCQUFrQjtBQUMzQnBCLElBQUFBLE1BQU0sR0FBRyxNQUFNLHlCQUFPO0FBQ3BCcUIsTUFBQUEsUUFBUSxFQUFFSixXQURVO0FBRXBCSyxNQUFBQSxJQUFJLEVBQUVOLFdBRmM7QUFHcEJPLE1BQUFBLFlBQVksRUFBRTlCO0FBSE0sS0FBUCxDQUFmO0FBS0QsR0FOUyxDQUFWO0FBT0ErQixFQUFBQSxTQUFTLENBQUMsa0JBQWtCO0FBQzFCLFFBQUl4QixNQUFKLEVBQVk7QUFDVixZQUFNQSxNQUFNLENBQUN5QixhQUFQLEVBQU47QUFDQXpCLE1BQUFBLE1BQU0sR0FBRyxJQUFUO0FBQ0Q7QUFDRixHQUxRLENBQVQ7QUFPQTBCLEVBQUFBLEVBQUUsQ0FBQyxpQ0FBRCxFQUFvQyxrQkFBa0I7QUFDdEQsVUFBTTFCLE1BQU0sQ0FBQzJCLEdBQVAsQ0FBVyxvQkFBWCxDQUFOO0FBQ0EsVUFBTUMsTUFBTSxHQUFHLE1BQU01QixNQUFNLENBQUM2QixDQUFQLENBQVMsZUFBVCxDQUFyQjtBQUNBLFVBQU1ELE1BQU0sQ0FBQ0UsT0FBUCxHQUFpQjVDLE1BQWpCLENBQXdCNkMsVUFBeEIsQ0FBbUNDLEdBQW5DLENBQXVDLGlCQUF2QyxDQUFOO0FBQ0QsR0FKQyxDQUFGO0FBS0QsQ0FyRE8sQ0FBUiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlbW90ZSB9IGZyb20gJ3dlYmRyaXZlcmlvJztcbmltcG9ydCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi4vLi4nO1xuaW1wb3J0IGNoYWlBc1Byb21pc2VkIGZyb20gJ2NoYWktYXMtcHJvbWlzZWQnO1xuaW1wb3J0IGNoYWkgZnJvbSAnY2hhaSc7XG5pbXBvcnQgU2ltY3RsIGZyb20gJ25vZGUtc2ltY3RsJztcbmltcG9ydCB7IEhPU1QsIFBPUlQsIE1PQ0hBX1RJTUVPVVQgfSBmcm9tICcuLi91dGlscyc7XG5cbmNoYWkuc2hvdWxkKCk7XG5jaGFpLnVzZShjaGFpQXNQcm9taXNlZCk7XG5cbmNvbnN0IFBMQVRGT1JNX1ZFUlNJT04gPSBwcm9jZXNzLmVudi5QTEFURk9STV9WRVJTSU9OIHx8ICcxNC4xJztcbmNvbnN0IERFVklDRV9OQU1FID0gcHJvY2Vzcy5lbnYuREVWSUNFX05BTUUgfHwgJ2lQaG9uZSAxMSBQcm8gTWF4JztcbmNvbnN0IENBUFMgPSB7XG4gIGJyb3dzZXJOYW1lOiAnQXBwaXVtU2FmYXJpJyxcbiAgcGxhdGZvcm1OYW1lOiAnaW9zJyxcbiAgJ3NhZmFyaTp1c2VTaW11bGF0b3InOiB0cnVlLFxuICAnc2FmYXJpOnBsYXRmb3JtVmVyc2lvbic6IFBMQVRGT1JNX1ZFUlNJT04sXG4gICdzYWZhcmk6ZGV2aWNlTmFtZSc6IERFVklDRV9OQU1FLFxufTtcblxuZGVzY3JpYmUoJ01vYmlsZSBTYWZhcmlEcml2ZXInLCBmdW5jdGlvbiAoKSB7XG4gIHRoaXMudGltZW91dChNT0NIQV9USU1FT1VUKTtcblxuICBsZXQgc2VydmVyO1xuICBsZXQgZHJpdmVyO1xuICBiZWZvcmUoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGlmIChwcm9jZXNzLmVudi5DSSkge1xuICAgICAgLy8gSW4gQXp1cmUgQ0kgdGhlIHN0dWZmIHVuZXhwZWN0ZWRseSBmYWlscyB3aXRoXG4gICAgICAvLyBcIlRoZSBkZXZpY2UgaXMgbm90IGNvbmZpZ3VyZWQgdG8gYWxsb3cgcmVtb3RlIGNvbnRyb2wgdmlhIFdlYkRyaXZlci4gVG8gZml4IHRoaXMsIHRvZ2dsZSAnQWxsb3cgUmVtb3RlIEF1dG9tYXRpb24nIGluIFNhZmFyaSdzIHNldHRpbmdzIChTZXR0aW5ncyBBcHAgPiBTYWZhcmkgPiBBZHZhbmNlZCkuXCJcbiAgICAgIC8vIGVycm9yXG4gICAgICByZXR1cm4gdGhpcy5za2lwKCk7XG4gICAgfVxuXG4gICAgLy8gUHJlYm9vdCBTaW11bGF0b3IgdG8gYXZvaWQgdW5leHBlY3RlZCB0aW1lb3V0c1xuICAgIGNvbnN0IHNpbWN0bCA9IG5ldyBTaW1jdGwoKTtcbiAgICBjb25zdCBhbGxEZXZpY2VzID0gYXdhaXQgc2ltY3RsLmdldERldmljZXMoUExBVEZPUk1fVkVSU0lPTiwgJ2lPUycpO1xuICAgIGNvbnN0IGRldmljZSA9IGFsbERldmljZXMuZmluZCgoe25hbWV9KSA9PiBuYW1lID09PSBERVZJQ0VfTkFNRSk7XG4gICAgaWYgKCFkZXZpY2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGZpbmQgJyR7REVWSUNFX05BTUV9JyBTaW11bGF0b3IgKCR7UExBVEZPUk1fVkVSU0lPTn0pYCk7XG4gICAgfVxuICAgIGlmIChkZXZpY2Uuc3RhdGUgIT09ICdCb290ZWQnKSB7XG4gICAgICBzaW1jdGwudWRpZCA9IGRldmljZS51ZGlkO1xuICAgICAgYXdhaXQgc2ltY3RsLmJvb3REZXZpY2UoKTtcbiAgICAgIGF3YWl0IHNpbWN0bC5zdGFydEJvb3RNb25pdG9yKCk7XG4gICAgfVxuXG4gICAgc2VydmVyID0gYXdhaXQgc3RhcnRTZXJ2ZXIoUE9SVCwgSE9TVCk7XG4gIH0pO1xuICBhZnRlcihhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHNlcnZlcikge1xuICAgICAgYXdhaXQgc2VydmVyLmNsb3NlKCk7XG4gICAgICBzZXJ2ZXIgPSBudWxsO1xuICAgIH1cbiAgfSk7XG4gIGJlZm9yZUVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGRyaXZlciA9IGF3YWl0IHJlbW90ZSh7XG4gICAgICBob3N0bmFtZTogSE9TVCxcbiAgICAgIHBvcnQ6IFBPUlQsXG4gICAgICBjYXBhYmlsaXRpZXM6IENBUFMsXG4gICAgfSk7XG4gIH0pO1xuICBhZnRlckVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGlmIChkcml2ZXIpIHtcbiAgICAgIGF3YWl0IGRyaXZlci5kZWxldGVTZXNzaW9uKCk7XG4gICAgICBkcml2ZXIgPSBudWxsO1xuICAgIH1cbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCBzdGFydCBhbmQgc3RvcCBhIHNlc3Npb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgYXdhaXQgZHJpdmVyLnVybCgnaHR0cHM6Ly9hcHBpdW0uaW8vJyk7XG4gICAgY29uc3QgYnV0dG9uID0gYXdhaXQgZHJpdmVyLiQoJyNkb3dubG9hZExpbmsnKTtcbiAgICBhd2FpdCBidXR0b24uZ2V0VGV4dCgpLnNob3VsZC5ldmVudHVhbGx5LmVxbCgnRG93bmxvYWQgQXBwaXVtJyk7XG4gIH0pO1xufSk7XG5cblxuIl0sImZpbGUiOiJ0ZXN0L2Z1bmN0aW9uYWwvbW9iaWxlLWRyaXZlci1lMmUtc3BlY3MuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vLi4ifQ==
|
package/build/test/utils.js
CHANGED
package/gulpfile.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
let gulp = require('gulp');
|
|
4
|
-
let boilerplate = require('appium
|
|
4
|
+
let boilerplate = require('@appium/gulp-plugins').boilerplate.use(gulp);
|
|
5
5
|
|
|
6
6
|
boilerplate({
|
|
7
|
-
build: 'appium-
|
|
7
|
+
build: 'appium-safari-driver',
|
|
8
|
+
files: ['index.js', 'lib/**/*.js', 'test/**/*.js', '!gulpfile.js'],
|
|
8
9
|
coverage: {
|
|
9
10
|
files: ['./test/unit/**/*-specs.js', '!./test/functional/**'],
|
|
10
11
|
verbose: true
|
package/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import SafariDriver from './lib/driver';
|
|
2
2
|
import { startServer } from './lib/server';
|
|
3
|
-
import yargs from 'yargs';
|
|
4
3
|
import { asyncify } from 'asyncbox';
|
|
5
4
|
|
|
6
5
|
const DEFAULT_HOST = 'localhost';
|
|
7
6
|
const DEFAULT_PORT = 4797;
|
|
8
7
|
|
|
9
8
|
async function main () {
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const getArgValue = (argName) => {
|
|
10
|
+
const argIndex = process.argv.indexOf(argName);
|
|
11
|
+
return argIndex > 0 ? process.argv[argIndex + 1] : null;
|
|
12
|
+
};
|
|
13
|
+
const port = parseInt(getArgValue('--port'), 10) || DEFAULT_PORT;
|
|
14
|
+
const host = getArgValue('--host') || DEFAULT_HOST;
|
|
12
15
|
return await startServer(port, host);
|
|
13
16
|
}
|
|
14
17
|
|
package/lib/commands/find.js
CHANGED
package/lib/commands/index.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import findCmds from './find';
|
|
2
|
+
import cookieCmds from './cookies';
|
|
3
|
+
import recordScreenCommands from './record-screen';
|
|
2
4
|
|
|
3
5
|
const commands = {};
|
|
4
6
|
Object.assign(
|
|
5
7
|
commands,
|
|
6
8
|
findCmds,
|
|
9
|
+
cookieCmds,
|
|
10
|
+
recordScreenCommands,
|
|
7
11
|
// add other command types here
|
|
8
12
|
);
|
|
9
13
|
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { util, fs, net, tempDir } from '@appium/support';
|
|
3
|
+
import { waitForCondition } from 'asyncbox';
|
|
4
|
+
import log from '../logger';
|
|
5
|
+
import Simctl from 'node-simctl';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const commands = {};
|
|
9
|
+
|
|
10
|
+
const STARTUP_INTERVAL_MS = 300;
|
|
11
|
+
const STARTUP_TIMEOUT_MS = 10 * 1000;
|
|
12
|
+
const DEFAULT_TIME_LIMIT_MS = 60 * 10 * 1000; // 10 minutes
|
|
13
|
+
const PROCESS_SHUTDOWN_TIMEOUT_MS = 10 * 1000;
|
|
14
|
+
const DEFAULT_EXT = '.mp4';
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async function uploadRecordedMedia (localFile, remotePath = null, uploadOptions = {}) {
|
|
18
|
+
if (_.isEmpty(remotePath)) {
|
|
19
|
+
const {size} = await fs.stat(localFile);
|
|
20
|
+
log.debug(`The size of the resulting screen recording is ${util.toReadableSizeString(size)}`);
|
|
21
|
+
return (await util.toInMemoryBase64(localFile)).toString();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const {user, pass, method, headers, fileFieldName, formFields} = uploadOptions;
|
|
25
|
+
const options = {
|
|
26
|
+
method: method || 'PUT',
|
|
27
|
+
headers,
|
|
28
|
+
fileFieldName,
|
|
29
|
+
formFields,
|
|
30
|
+
};
|
|
31
|
+
if (user && pass) {
|
|
32
|
+
options.auth = {user, pass};
|
|
33
|
+
}
|
|
34
|
+
await net.uploadFile(localFile, remotePath, options);
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const VIDEO_FILES = new Set();
|
|
39
|
+
process.on('exit', () => {
|
|
40
|
+
for (const videoFile of VIDEO_FILES) {
|
|
41
|
+
try {
|
|
42
|
+
fs.rimrafSync(videoFile);
|
|
43
|
+
} catch (ign) {}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
class ScreenRecorder {
|
|
48
|
+
constructor (udid, videoPath, opts = {}) {
|
|
49
|
+
this._process = null;
|
|
50
|
+
this._udid = udid;
|
|
51
|
+
this._videoPath = videoPath;
|
|
52
|
+
this._codec = opts.codec;
|
|
53
|
+
this._display = opts.display;
|
|
54
|
+
this._mask = opts.mask;
|
|
55
|
+
this._timeLimitMs = opts.timeLimit > 0 ? opts.timeLimit * 1000 : DEFAULT_TIME_LIMIT_MS;
|
|
56
|
+
this._timer = null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async getVideoPath () {
|
|
60
|
+
if (await fs.exists(this._videoPath)) {
|
|
61
|
+
VIDEO_FILES.add(this._videoPath);
|
|
62
|
+
return this._videoPath;
|
|
63
|
+
}
|
|
64
|
+
return '';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get isRunning () {
|
|
68
|
+
return !!(this._process?.isRunning);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async _enforceTermination () {
|
|
72
|
+
if (this.isRunning) {
|
|
73
|
+
log.debug('Force-stopping the currently running video recording');
|
|
74
|
+
try {
|
|
75
|
+
await this._process.stop('SIGKILL');
|
|
76
|
+
} catch (ign) {}
|
|
77
|
+
}
|
|
78
|
+
this._process = null;
|
|
79
|
+
const videoPath = await this.getVideoPath();
|
|
80
|
+
if (videoPath) {
|
|
81
|
+
await fs.rimraf(videoPath);
|
|
82
|
+
VIDEO_FILES.delete(videoPath);
|
|
83
|
+
}
|
|
84
|
+
return '';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async start () {
|
|
88
|
+
const args = [
|
|
89
|
+
this._udid, 'recordVideo'
|
|
90
|
+
];
|
|
91
|
+
if (this._display) {
|
|
92
|
+
args.push('--display', this._display);
|
|
93
|
+
}
|
|
94
|
+
if (this._codec) {
|
|
95
|
+
args.push('--codec', this._codec);
|
|
96
|
+
}
|
|
97
|
+
if (this._mask) {
|
|
98
|
+
args.push('--mask', this._mask);
|
|
99
|
+
}
|
|
100
|
+
args.push('--force', this._videoPath);
|
|
101
|
+
this._process = await new Simctl().exec('io', {
|
|
102
|
+
args,
|
|
103
|
+
asynchronous: true,
|
|
104
|
+
});
|
|
105
|
+
log.debug(`Starting video recording with arguments: ${util.quote(args)}`);
|
|
106
|
+
this._process.on('output', (stdout, stderr) => {
|
|
107
|
+
const line = _.trim(stdout || stderr);
|
|
108
|
+
if (line) {
|
|
109
|
+
log.debug(`[recordVideo@${this._udid.substring(0, 8)}] ${line}`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
this._process.once('exit', async (code, signal) => {
|
|
113
|
+
this._process = null;
|
|
114
|
+
if (code === 0) {
|
|
115
|
+
log.debug('Screen recording exited without errors');
|
|
116
|
+
} else {
|
|
117
|
+
await this._enforceTermination();
|
|
118
|
+
log.warn(`Screen recording exited with error code ${code}, signal ${signal}`);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
await this._process.start(0);
|
|
122
|
+
try {
|
|
123
|
+
await waitForCondition(async () => {
|
|
124
|
+
if (!this.isRunning) {
|
|
125
|
+
throw new Error();
|
|
126
|
+
}
|
|
127
|
+
return !!(await this.getVideoPath());
|
|
128
|
+
}, {
|
|
129
|
+
waitMs: STARTUP_TIMEOUT_MS,
|
|
130
|
+
intervalMs: STARTUP_INTERVAL_MS,
|
|
131
|
+
});
|
|
132
|
+
} catch (e) {
|
|
133
|
+
await this._enforceTermination();
|
|
134
|
+
log.errorAndThrow(`The expected screen record file '${this._videoPath}' does not exist after ${STARTUP_TIMEOUT_MS}ms. ` +
|
|
135
|
+
`Check the server log for more details`);
|
|
136
|
+
}
|
|
137
|
+
this._timer = setTimeout(async () => {
|
|
138
|
+
if (this.isRunning) {
|
|
139
|
+
try {
|
|
140
|
+
await this.stop();
|
|
141
|
+
} catch (e) {
|
|
142
|
+
log.error(e);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}, this._timeLimitMs);
|
|
146
|
+
log.info(`The video recording has started. Will timeout in ${this._timeLimitMs}ms`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async stop (force = false) {
|
|
150
|
+
if (this._timer) {
|
|
151
|
+
clearTimeout(this._timer);
|
|
152
|
+
this._timer = null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (force) {
|
|
156
|
+
return await this._enforceTermination();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!this.isRunning) {
|
|
160
|
+
log.debug('Screen recording is not running. Returning the recently recorded video');
|
|
161
|
+
return await this.getVideoPath();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
await this._process.stop('SIGINT', PROCESS_SHUTDOWN_TIMEOUT_MS);
|
|
166
|
+
} catch (e) {
|
|
167
|
+
await this._enforceTermination();
|
|
168
|
+
throw new Error(`Screen recording has failed to stop after ${PROCESS_SHUTDOWN_TIMEOUT_MS}ms`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return await this.getVideoPath();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function extractSimulatorUdid (caps) {
|
|
176
|
+
if (caps['safari:useSimulator'] === false) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const allDevices = _.flatMap(_.values(await new Simctl().getDevices(null, 'iOS')));
|
|
181
|
+
for (const {name, udid, state, sdk} of allDevices) {
|
|
182
|
+
if (state !== 'Booted') {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (_.toLower(caps['safari:deviceUDID']) === _.toLower(udid)) {
|
|
187
|
+
return udid;
|
|
188
|
+
}
|
|
189
|
+
if (_.toLower(caps['safari:deviceName']) === _.toLower(name) &&
|
|
190
|
+
(caps['safari:platformVersion'] && caps['safari:platformVersion'] === sdk
|
|
191
|
+
|| !caps['safari:platformVersion'])) {
|
|
192
|
+
return udid;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @typedef {Object} StartRecordingOptions
|
|
202
|
+
*
|
|
203
|
+
* @property {?string} codec [hevc] - Specifies the codec type: "h264" or "hevc"
|
|
204
|
+
* @property {?string} display [internal] - Supports "internal" or "external". Default is "internal"
|
|
205
|
+
* @property {?string} mask - For non-rectangular displays, handle the mask by policy:
|
|
206
|
+
* - ignored: The mask is ignored and the unmasked framebuffer is saved.
|
|
207
|
+
* - alpha: Not supported, but retained for compatibility; the mask is rendered black.
|
|
208
|
+
* - black: The mask is rendered black.
|
|
209
|
+
* @property {string|number} timeLimit [600] - The maximum recording time, in seconds. The default
|
|
210
|
+
* value is 600 seconds (10 minutes).
|
|
211
|
+
* @property {boolean} forceRestart [true] - Whether to ignore the call if a screen recording is currently running
|
|
212
|
+
* (`false`) or to start a new recording immediately and terminate the existing one if running (`true`).
|
|
213
|
+
*/
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Record the Simulator's display in background while the automated test is running.
|
|
217
|
+
* This method uses `xcrun simctl io recordVideo` helper under the hood.
|
|
218
|
+
* Check the output of `xcrun simctl io` command for more details.
|
|
219
|
+
*
|
|
220
|
+
* @param {?StartRecordingOptions} options - The available options.
|
|
221
|
+
* @throws {Error} If screen recording has failed to start or is not supported for the destination device.
|
|
222
|
+
*/
|
|
223
|
+
commands.startRecordingScreen = async function startRecordingScreen (options = {}) {
|
|
224
|
+
const {
|
|
225
|
+
timeLimit,
|
|
226
|
+
codec,
|
|
227
|
+
display,
|
|
228
|
+
mask,
|
|
229
|
+
forceRestart = true,
|
|
230
|
+
} = options;
|
|
231
|
+
if (this._screenRecorder?.isRunning) {
|
|
232
|
+
log.info('The screen recording is already running');
|
|
233
|
+
if (!forceRestart) {
|
|
234
|
+
log.info('Doing nothing');
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
log.info('Forcing the active screen recording to stop');
|
|
238
|
+
await this._screenRecorder.stop(true);
|
|
239
|
+
}
|
|
240
|
+
this._screenRecorder = null;
|
|
241
|
+
|
|
242
|
+
const udid = await extractSimulatorUdid(this.caps);
|
|
243
|
+
if (!udid) {
|
|
244
|
+
throw new Error('Cannot determine Simulator UDID to record the video from. ' +
|
|
245
|
+
'Double check your session capabilities');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const videoPath = await tempDir.path({
|
|
249
|
+
prefix: util.uuidV4().substring(0, 8),
|
|
250
|
+
suffix: DEFAULT_EXT,
|
|
251
|
+
});
|
|
252
|
+
this._screenRecorder = new ScreenRecorder(udid, videoPath, {
|
|
253
|
+
timeLimit: parseInt(timeLimit, 10),
|
|
254
|
+
codec,
|
|
255
|
+
display,
|
|
256
|
+
mask,
|
|
257
|
+
});
|
|
258
|
+
try {
|
|
259
|
+
await this._screenRecorder.start();
|
|
260
|
+
} catch (e) {
|
|
261
|
+
this._screenRecorder = null;
|
|
262
|
+
throw e;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @typedef {Object} StopRecordingOptions
|
|
268
|
+
*
|
|
269
|
+
* @property {?string} remotePath - The path to the remote location, where the resulting video should be uploaded.
|
|
270
|
+
* The following protocols are supported: http/https, ftp.
|
|
271
|
+
* Null or empty string value (the default setting) means the content of resulting
|
|
272
|
+
* file should be encoded as Base64 and passed as the endpoint response value.
|
|
273
|
+
* An exception will be thrown if the generated media file is too big to
|
|
274
|
+
* fit into the available process memory.
|
|
275
|
+
* @property {?string} user - The name of the user for the remote authentication.
|
|
276
|
+
* @property {?string} pass - The password for the remote authentication.
|
|
277
|
+
* @property {?string} method - The http multipart upload method name. The 'PUT' one is used by default.
|
|
278
|
+
* @property {?Object} headers - Additional headers mapping for multipart http(s) uploads
|
|
279
|
+
* @property {?string} fileFieldName [file] - The name of the form field, where the file content BLOB should be stored for
|
|
280
|
+
* http(s) uploads
|
|
281
|
+
* @property {?Object|Array<Pair>} formFields - Additional form fields for multipart http(s) uploads
|
|
282
|
+
*/
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Stop recording the screen.
|
|
286
|
+
* If no screen recording has been started before then the method returns an empty string.
|
|
287
|
+
*
|
|
288
|
+
* @param {?StopRecordingOptions} options - The available options.
|
|
289
|
+
* @returns {string} Base64-encoded content of the recorded media file if 'remotePath'
|
|
290
|
+
* parameter is falsy or an empty string.
|
|
291
|
+
* @throws {Error} If there was an error while getting the name of a media file
|
|
292
|
+
* or the file content cannot be uploaded to the remote location
|
|
293
|
+
* or screen recording is not supported on the device under test.
|
|
294
|
+
*/
|
|
295
|
+
commands.stopRecordingScreen = async function stopRecordingScreen (options = {}) {
|
|
296
|
+
if (!this._screenRecorder) {
|
|
297
|
+
log.info('No screen recording has been started. Doing nothing');
|
|
298
|
+
return '';
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
log.debug('Retrieving the resulting video data');
|
|
302
|
+
const videoPath = await this._screenRecorder.stop();
|
|
303
|
+
if (!videoPath) {
|
|
304
|
+
log.info('No video data is found. Returning an empty string');
|
|
305
|
+
return '';
|
|
306
|
+
}
|
|
307
|
+
return await uploadRecordedMedia(videoPath, options.remotePath, options);
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export default commands;
|
package/lib/driver.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
|
-
import { BaseDriver } from 'appium
|
|
2
|
+
import { BaseDriver } from '@appium/base-driver';
|
|
3
3
|
import log from './logger';
|
|
4
4
|
import SafariDriverServer from './safari';
|
|
5
5
|
import { desiredCapConstraints } from './desired-caps';
|
|
@@ -11,6 +11,8 @@ const NO_PROXY = [
|
|
|
11
11
|
['POST', new RegExp('^/session/[^/]+/appium')],
|
|
12
12
|
['POST', new RegExp('^/session/[^/]+/element/[^/]+/elements?$')],
|
|
13
13
|
['POST', new RegExp('^/session/[^/]+/elements?$')],
|
|
14
|
+
|
|
15
|
+
['DELETE', new RegExp('^/session/[^/]+/cookie$')],
|
|
14
16
|
];
|
|
15
17
|
|
|
16
18
|
class SafariDriver extends BaseDriver {
|
|
@@ -38,6 +40,7 @@ class SafariDriver extends BaseDriver {
|
|
|
38
40
|
this.safari = null;
|
|
39
41
|
this.proxyReqRes = null;
|
|
40
42
|
this.isProxyActive = false;
|
|
43
|
+
this._screenRecorder = null;
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
proxyActive () {
|
|
@@ -68,7 +71,8 @@ class SafariDriver extends BaseDriver {
|
|
|
68
71
|
|
|
69
72
|
async deleteSession () {
|
|
70
73
|
log.info('Ending Safari session');
|
|
71
|
-
await this.
|
|
74
|
+
await this._screenRecorder?.stop(true);
|
|
75
|
+
await this.safari?.stop();
|
|
72
76
|
this.resetState();
|
|
73
77
|
|
|
74
78
|
await super.deleteSession();
|
package/lib/logger.js
CHANGED
package/lib/safari.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os from 'os';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { JWProxy, errors } from 'appium
|
|
4
|
-
import { fs, logger, util } from 'appium
|
|
3
|
+
import { JWProxy, errors } from '@appium/base-driver';
|
|
4
|
+
import { fs, logger, util } from '@appium/support';
|
|
5
5
|
import { SubProcess } from 'teen_process';
|
|
6
6
|
import { waitForCondition } from 'asyncbox';
|
|
7
7
|
import { findAPortNotInUse } from 'portscanner';
|
package/lib/server.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import log from './logger';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
server as baseServer, routeConfiguringFunction as makeRouter
|
|
4
|
+
} from '@appium/base-driver';
|
|
3
5
|
import SafariDriver from './driver';
|
|
4
6
|
|
|
5
7
|
async function startServer (port, address) {
|