54 | * @link https://github.com/appium/python-client/blob/master/appium/webdriver/webdriver.py
55 | *
56 | */
57 | public function setLocation($latitude, $longitude, $altitude)
58 | {
59 | $lat = strval($latitude);
60 | $lon = strval($longitude);
61 | $alt = strval($altitude);
62 | $data = [
63 | 'location' => [
64 | 'latitude' => $lat,
65 | 'longitude' => $lon,
66 | 'altitude' => $alt
67 | ]
68 | ];
69 | return $this->driverCommand(BaseConstants::$POST, '/location', $data);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Only one feature or change per pull request
4 |
5 | Make pull requests only one feature or change at the time. Make pull requests from feature branch. Pull requests should not come from your master branch.
6 |
7 | For example you have fixed a bug. You also have optimized some code. Optimization is not related to a bug. These should be submitted as separate pull requests. This way I can easily choose what to include. It is also easier to understand the code changes.
8 |
9 | ## Write meaningful commit messages
10 |
11 | Proper commit message is full sentence. It starts with capital letter but does not end with period. Headlines do not end with period. The GitHub default `Update filename.js` is not enough. When needed include also longer explanation what the commit does.
12 |
13 | ```
14 | Capitalized, short (50 chars or less) summary
15 |
16 | More detailed explanatory text, if necessary. Wrap it to about 72
17 | characters or so. In some contexts, the first line is treated as the
18 | subject of an email and the rest of the text as the body. The blank
19 | line separating the summary from the body is critical (unless you omit
20 | the body entirely); tools like rebase can get confused if you run the
21 | two together.
22 | ```
23 |
24 | When in doubt see Tim Pope's blogpost [A Note About Git Commit Messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
25 |
26 | ## Send coherent history
27 |
28 | Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.
29 |
30 | ## Follow the existing coding standards
31 |
32 | When contributing to open source project it is polite to follow the original authors coding standars. They might be different than yours. It is not a holy war. This project uses **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)**
33 |
34 | ## Running Tests
35 |
36 | You can run individual tests either manually...
37 |
38 | ``` bash
39 | $ composer phplint
40 | $ composer phpcs
41 | $ composer phpunit
42 | ```
43 |
44 | ... or automatically on every code change. You will need [entr](http://entrproject.org/) for this to work.
45 |
46 | ``` bash
47 | $ composer watch
48 | ```
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at ccc@me.io. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/src/TestCase/Element.php:
--------------------------------------------------------------------------------
1 | descend($value['ELEMENT']);
27 |
28 | return new static($driver, $url);
29 | }
30 |
31 | // override to return Appium element
32 |
33 | /**
34 | * @param \PHPUnit_Extensions_Selenium2TestCase_ElementCriteria $criteria
35 | * @return Element
36 | */
37 | public function element(\PHPUnit_Extensions_Selenium2TestCase_ElementCriteria $criteria)
38 | {
39 | $value = $this->postCommand('element', $criteria);
40 |
41 | return Element::fromResponseValue($value, $this->getSessionUrl()->descend('element'), $this->driver);
42 | }
43 |
44 | /**
45 | * @param \PHPUnit_Extensions_Selenium2TestCase_ElementCriteria $criteria
46 | * @return array
47 | */
48 | public function elements(\PHPUnit_Extensions_Selenium2TestCase_ElementCriteria $criteria)
49 | {
50 | $values = $this->postCommand('elements', $criteria);
51 |
52 | $elements = [];
53 | foreach ($values as $value) {
54 | $elements[] = Element::fromResponseValue($value, $this->getSessionUrl()->descend('element'), $this->driver);
55 | }
56 |
57 | return $elements;
58 | }
59 |
60 | /**
61 | * @param string $strategy
62 | * @param string $value
63 | * @return Element
64 | */
65 | public function by($strategy, $value)
66 | {
67 | $el = $this->element($this->using($strategy)->value($value));
68 |
69 | return $el;
70 | }
71 |
72 | /**
73 | * @return \PHPUnit_Extensions_Selenium2TestCase_URL|string
74 | */
75 | protected function getSessionUrl()
76 | {
77 | return $this->url;
78 | }
79 |
80 | /**
81 | * @param $value
82 | *
83 | * @return \PHPUnit_Extensions_Selenium2TestCase_Response
84 | */
85 | public function setValueImmediate($value)
86 | {
87 | $data = [
88 | 'id' => $this->getId(),
89 | 'value' => $value,
90 | ];
91 | $url = $this->getSessionUrl()->ascend()->ascend()->descend('appium')->descend('element')->descend($this->getId())->descend('value');
92 |
93 | return $this->driver->curl('POST', $url, $data);
94 | }
95 |
96 |
97 | /**
98 | * @param $keys
99 | *
100 | * @return \PHPUnit_Extensions_Selenium2TestCase_Response
101 | */
102 | public function replaceValue($keys)
103 | {
104 | $data = [
105 | 'id' => $this->getId(),
106 | 'value' => [$keys],
107 | ];
108 | $url = $this->getSessionUrl()->ascend()->ascend()->descend('appium')->descend('element')->descend($this->getId())->descend('replace_value');
109 |
110 | return $this->driver->curl('POST', $url, $data);
111 | }
112 |
113 | /**
114 | * @return string content of this element
115 | */
116 | public function getText()
117 | {
118 | $data = array(
119 | 'id' => $this->getId()
120 | );
121 | $url = $this->getSessionUrl()->ascend()->ascend()->descend('element')->descend($this->getId())->descend('text');
122 | $response = $this->driver->curl('GET', $url, $data);
123 | return $response->getValue();
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/cmd/Parser/Helpers/TextTable.php:
--------------------------------------------------------------------------------
1 | 'L',
25 | 'type' => 'C',
26 | ];
27 |
28 | /**
29 | * @param array $header The header array [key => label, ...]
30 | * @param array $content Content
31 | * @param bool $align Alignment optios [key => L|R|C, ...]
32 | */
33 | public function __construct($header = null, $content = [], $align = false)
34 | {
35 | if ($header) {
36 | $this->header = $header;
37 | } elseif ($content) {
38 | foreach ($content[0] as $key => $value) {
39 | $this->header[$key] = $key;
40 | }
41 | }
42 | foreach ($this->header as $key => $label) {
43 | $this->len[$key] = strlen($label);
44 | }
45 | if (is_array($align)) {
46 | $this->setAlgin($align);
47 | }
48 | $this->addData($content);
49 | }
50 |
51 | /**
52 | * Overwrite the alignment array
53 | *
54 | * @param array $align Alignment optios [key => L|R|C, ...]
55 | */
56 | public function setAlgin($align)
57 | {
58 | $this->align = $align;
59 | }
60 |
61 | /**
62 | * Add data to the table
63 | *
64 | * @param array $content Content
65 | *
66 | * @return \AppiumCodeceptionCLI\Parser\Helpers\TextTable
67 | */
68 | public function addData($content)
69 | {
70 | foreach ($content as &$row) {
71 | foreach ($this->header as $key => $value) {
72 | if (!isset($row[$key])) {
73 | $row[$key] = '-';
74 | } elseif (strlen($row[$key]) > $this->maxlen) {
75 | $this->len[$key] = $this->maxlen;
76 | $row[$key] = substr($row[$key], 0, $this->maxlen - 3) . '...';
77 | } elseif (strlen($row[$key]) > $this->len[$key]) {
78 | $this->len[$key] = strlen($row[$key]);
79 | }
80 | }
81 | }
82 | $this->data = $this->data + $content;
83 |
84 | return $this;
85 | }
86 |
87 | /**
88 | * Add a delimiter
89 | *
90 | * @return string
91 | */
92 | private function renderDelimiter()
93 | {
94 | $res = '|';
95 | foreach ($this->len as $key => $l) {
96 | $res .= (isset($this->align[$key]) && ($this->align[$key] == 'C' || $this->align[$key] == 'L') ? ':' : ' ')
97 | . str_repeat('-', $l)
98 | . (isset($this->align[$key]) && ($this->align[$key] == 'C' || $this->align[$key] == 'R') ? ':' : ' ')
99 | . '|';
100 | }
101 |
102 | return $res . "\r\n";
103 | }
104 |
105 | /**
106 | * Render a single row
107 | *
108 | * @param array $row
109 | *
110 | * @return string
111 | */
112 | private function renderRow($row)
113 | {
114 | $res = '|';
115 | foreach ($this->len as $key => $l) {
116 | $res .= ' ' . $row[$key] . ($l > strlen($row[$key]) ? str_repeat(' ', $l - strlen($row[$key])) : '') . ' |';
117 | }
118 |
119 | return $res . "\r\n";
120 | }
121 |
122 | /**
123 | * Render the table
124 | *
125 | * @param array $content Additional table content
126 | *
127 | * @return string
128 | */
129 | public function render($content = [])
130 | {
131 | $this->addData($content);
132 | $res = $this->renderRow($this->header)
133 | . $this->renderDelimiter();
134 | foreach ($this->data as $row) {
135 | $res .= $this->renderRow($row);
136 | }
137 |
138 | return $res;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### NetBeans template
3 | nbproject/private/
4 | build/
5 | nbbuild/
6 | dist/
7 | nbdist/
8 | nbactions.xml
9 | .nb-gradle/
10 | ### Linux template
11 | *~
12 |
13 | # temporary files which can be created if a process still has a handle open of a deleted file
14 | .fuse_hidden*
15 |
16 | # KDE directory preferences
17 | .directory
18 |
19 | # Linux trash folder which might appear on any partition or disk
20 | .Trash-*
21 | ### JetBrains template
22 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
23 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
24 |
25 | # User-specific stuff:
26 | .idea/workspace.xml
27 | .idea/tasks.xml
28 | .idea/dictionaries
29 | .idea/vcs.xml
30 | .idea/jsLibraryMappings.xml
31 |
32 | # Sensitive or high-churn files:
33 | .idea/dataSources.ids
34 | .idea/dataSources.xml
35 | .idea/dataSources.local.xml
36 | .idea/sqlDataSources.xml
37 | .idea/dynamic.xml
38 | .idea/uiDesigner.xml
39 |
40 | # Gradle:
41 | .idea/gradle.xml
42 | .idea/libraries
43 |
44 | # Mongo Explorer plugin:
45 | .idea/mongoSettings.xml
46 |
47 | ## File-based project format:
48 | *.iws
49 |
50 | ## Plugin-specific files:
51 |
52 | # IntelliJ
53 | /out/
54 |
55 | # mpeltonen/sbt-idea plugin
56 | .idea_modules/
57 |
58 | # JIRA plugin
59 | atlassian-ide-plugin.xml
60 |
61 | # Crashlytics plugin (for Android Studio and IntelliJ)
62 | com_crashlytics_export_strings.xml
63 | crashlytics.properties
64 | crashlytics-build.properties
65 | fabric.properties
66 | ### Symfony template
67 | # Cache and logs (Symfony2)
68 | /app/cache/*
69 | /app/logs/*
70 | !app/cache/.gitkeep
71 | !app/logs/.gitkeep
72 |
73 | # Email spool folder
74 | /app/spool/*
75 |
76 | # Cache, session files and logs (Symfony3)
77 | /var/cache/*
78 | /var/logs/*
79 | /var/sessions/*
80 | !var/cache/.gitkeep
81 | !var/logs/.gitkeep
82 | !var/sessions/.gitkeep
83 |
84 | # Parameters
85 | /app/config/parameters.yml
86 | /app/config/parameters.ini
87 |
88 | # Managed by Composer
89 | /app/bootstrap.php.cache
90 | /var/bootstrap.php.cache
91 | !bin/console
92 | !bin/symfony_requirements
93 | /vendor/
94 |
95 | # Assets and user uploads
96 | /web/bundles/
97 | /web/uploads/
98 |
99 | # Assets managed by Bower
100 | /web/assets/vendor/
101 |
102 | # PHPUnit
103 | /app/phpunit.xml
104 |
105 | # Build data
106 | /build/
107 |
108 | # Composer PHAR
109 | /composer.phar
110 |
111 | # Backup entities generated with doctrine:generate:entities command
112 | */Entity/*~
113 | ### SublimeText template
114 | # cache files for sublime text
115 | *.tmlanguage.cache
116 | *.tmPreferences.cache
117 | *.stTheme.cache
118 |
119 | # workspace files are user-specific
120 | *.sublime-workspace
121 |
122 | # project files should be checked into the repository, unless a significant
123 | # proportion of contributors will probably not be using SublimeText
124 | # *.sublime-project
125 |
126 | # sftp configuration file
127 | sftp-config.json
128 |
129 | # Package control specific files
130 | Package Control.last-run
131 | Package Control.ca-list
132 | Package Control.ca-bundle
133 | Package Control.system-ca-bundle
134 | Package Control.cache/
135 | Package Control.ca-certs/
136 | bh_unicode_properties.cache
137 |
138 | # Sublime-github package stores a github token in this file
139 | # https://packagecontrol.io/packages/sublime-github
140 | GitHub.sublime-settings
141 | ### Vim template
142 | # swap
143 | [._]*.s[a-w][a-z]
144 | [._]s[a-w][a-z]
145 | # session
146 | Session.vim
147 | # temporary
148 | .netrwhist
149 | *~
150 | # auto-generated tag files
151 | tags
152 | ### OSX template
153 | *.DS_Store
154 | .AppleDouble
155 | .LSOverride
156 |
157 | # Icon must end with two \r
158 | Icon
159 |
160 | # Thumbnails
161 | ._*
162 |
163 | # Files that might appear in the root of a volume
164 | .DocumentRevisions-V100
165 | .fseventsd
166 | .Spotlight-V100
167 | .TemporaryItems
168 | .Trashes
169 | .VolumeIcon.icns
170 | .com.apple.timemachine.donotpresent
171 |
172 | # Directories potentially created on remote AFP share
173 | .AppleDB
174 | .AppleDesktop
175 | Network Trash Folder
176 | Temporary Items
177 | .apdisk
178 | ### Vagrant template
179 | .vagrant/
180 | ### Windows template
181 | # Windows image file caches
182 | Thumbs.db
183 | ehthumbs.db
184 |
185 | # Folder config file
186 | Desktop.ini
187 |
188 | # Recycle Bin used on file shares
189 | $RECYCLE.BIN/
190 |
191 | # Windows Installer files
192 | *.cab
193 | *.msi
194 | *.msm
195 | *.msp
196 |
197 | # Windows shortcuts
198 | *.lnk
199 |
200 | composer.phar
201 | package/codecept.phar
202 | .idea
203 | .phplint-cache
204 | node_modules
--------------------------------------------------------------------------------
/src/Traits/Elm.php:
--------------------------------------------------------------------------------
1 | AppiumDriver, $this->getSessionUrl());
20 | }
21 |
22 |
23 | /**
24 | * @param Element $element that accepts a string
25 | * @param string $keys send to $element
26 | * @return \PHPUnit_Extensions_Selenium2TestCase_Response
27 | */
28 | public function sendKeys($element, $keys)
29 | {
30 | return $element->setValueImmediate($keys);
31 | }
32 |
33 | /**
34 | * @param $value
35 | *
36 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
37 | */
38 | public function byIOSUIAutomation($value)
39 | {
40 | return $this->TestCaseElm()->by('-ios uiautomation', $value);
41 | }
42 |
43 | /**
44 | * @param $value
45 | *
46 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
47 | */
48 | public function byIOSPredicateString($value)
49 | {
50 | return $this->TestCaseElm()->by('-ios predicate string', $value);
51 | }
52 |
53 | /**
54 | * @param $value
55 | *
56 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
57 | */
58 | public function byAndroidUIAutomator($value)
59 | {
60 | return $this->TestCaseElm()->by('-android uiautomator', $value);
61 | }
62 |
63 | /**
64 | * @param $value
65 | *
66 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
67 | */
68 | public function byAccessibilityId($value)
69 | {
70 | return $this->TestCaseElm()->by('accessibility id', $value);
71 | }
72 |
73 | /**
74 | * @param string $value e.g. 'container'
75 | *
76 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
77 | */
78 | public function byClassName($value)
79 | {
80 | return $this->TestCaseElm()->by('class name', $value);
81 | }
82 |
83 | /**
84 | * @param string $value e.g. 'div.container'
85 | *
86 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
87 | */
88 | public function byCssSelector($value)
89 | {
90 | return $this->TestCaseElm()->by('css selector', $value);
91 | }
92 |
93 | /**
94 | * @param string $value e.g. 'uniqueId'
95 | *
96 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
97 | */
98 | public function byId($value)
99 | {
100 | return $this->TestCaseElm()->by('id', $value);
101 | }
102 |
103 | /**
104 | * @param string $value e.g. 'Link text'
105 | *
106 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
107 | */
108 | public function byLinkText($value)
109 | {
110 | return $this->TestCaseElm()->by('link text', $value);
111 | }
112 |
113 | /**
114 | * @param string $value e.g. 'Link te'
115 | *
116 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
117 | */
118 | public function byPartialLinkText($value)
119 | {
120 | return $this->TestCaseElm()->by('partial link text', $value);
121 | }
122 |
123 | /**
124 | * @param string $value e.g. 'email_address'
125 | *
126 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
127 | */
128 | public function byName($value)
129 | {
130 | return $this->TestCaseElm()->by('name', $value);
131 | }
132 |
133 | /**
134 | * @param string $value e.g. 'body'
135 | *
136 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
137 | */
138 | public function byTag($value)
139 | {
140 | return $this->TestCaseElm()->by('tag name', $value);
141 | }
142 |
143 | /**
144 | * @param string $value e.g. '/div[@attribute="value"]'
145 | *
146 | * @return \Appium\TestCase\Element|\PHPUnit_Extensions_Selenium2TestCase_Element
147 | */
148 | public function byXPath($value)
149 | {
150 | return $this->TestCaseElm()->by('xpath', $value);
151 | }
152 |
153 | /**
154 | * @param $value
155 | * @return \Appium\TestCase\Element
156 | * @link https://github.com/appium/python-client/blob/master/appium/webdriver/webdriver.py
157 | */
158 | public function byIOSClassChain($value)
159 | {
160 | return $this->TestCaseElm()->by('-ios class chain', $value);
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/TestCase/TouchAction.php:
--------------------------------------------------------------------------------
1 | sessionUrl = $sessionUrl;
24 | $this->driver = $driver;
25 | $this->actions = [];
26 |
27 | return $this;
28 | }
29 |
30 | /**
31 | * @return \Appium\TestCase\Element
32 | */
33 | public function TestCaseElement()
34 | {
35 | return new Element($this->driver, $this->sessionUrl);
36 | }
37 |
38 | /**
39 | * @param $params
40 | *
41 | * @return $this
42 | */
43 | public function tap($params)
44 | {
45 | $options = $this->getOptions($params);
46 |
47 | if (array_key_exists('count', $params)) {
48 | $options['count'] = $params['count'];
49 | } else {
50 | $options['count'] = 1;
51 | }
52 |
53 | $this->addAction('tap', $options);
54 |
55 | return $this;
56 | }
57 |
58 | /**
59 | * @param $params
60 | *
61 | * @return $this
62 | */
63 | public function press($params)
64 | {
65 | $options = $this->getOptions($params);
66 |
67 | $this->addAction('press', $options);
68 |
69 | return $this;
70 | }
71 |
72 | /**
73 | * @param $params
74 | *
75 | * @return $this
76 | */
77 | public function longPress($params)
78 | {
79 | $options = $this->getOptions($params);
80 |
81 | if (array_key_exists('duration', $params)) {
82 | $options['duration'] = $params['duration'];
83 | } else {
84 | $options['duration'] = 800;
85 | }
86 |
87 | $this->addAction('longPress', $options);
88 |
89 | return $this;
90 | }
91 |
92 | /**
93 | * @param $params
94 | *
95 | * @return $this
96 | */
97 | public function moveTo($params)
98 | {
99 | $options = $this->getOptions($params);
100 |
101 | $this->addAction('moveTo', $options);
102 |
103 | return $this;
104 | }
105 |
106 | /**
107 | * @param $params
108 | *
109 | * @return $this
110 | */
111 | public function wait($params)
112 | {
113 | $options = [];
114 |
115 | if (gettype($params) == 'array') {
116 | if (array_key_exists('ms', $params)) {
117 | $options['ms'] = $params['ms'];
118 | } else {
119 | $options['ms'] = 0;
120 | }
121 | } else {
122 | $options['ms'] = $params;
123 | }
124 |
125 | $this->addAction('wait', $options);
126 |
127 | return $this;
128 | }
129 |
130 | /**
131 | * @return $this
132 | */
133 | public function release()
134 | {
135 | $this->addAction('release', []);
136 |
137 | return $this;
138 | }
139 |
140 | /**
141 | * @return \PHPUnit_Extensions_Selenium2TestCase_Response
142 | */
143 | public function perform()
144 | {
145 | $params = [
146 | 'actions' => $this->actions,
147 | ];
148 | $url = $this->sessionUrl->descend('touch')->descend('perform');
149 |
150 | return $this->driver->curl('POST', $url, $params);
151 | }
152 |
153 | /**
154 | * @return array
155 | */
156 | public function getJSONWireGestures()
157 | {
158 | $actions = [];
159 | foreach ($this->actions as $action) {
160 | $actions[] = $action;
161 | }
162 |
163 | return $actions;
164 | }
165 |
166 | /**
167 | * Get options and create element depending on the selector type sent in the options.
168 | *
169 | * @param $params
170 | *
171 | * @return array
172 | */
173 | public function getOptions($params)
174 | {
175 | $opts = [];
176 |
177 | if (array_key_exists('element', $params) && $params['element'] != null) {
178 | if (is_array($params['element']) && isset($params['element']['type']) && isset($params['element']['value'])) {
179 | /*
180 | * Select the type of the selector sent in the options: ['element' => ['type' => 'xpath', 'value' => '//your_xpath']]
181 | */
182 | $opts['element'] = $this->TestCaseElement()->by($params['element']['type'], $params['element']['value'])->getId();
183 | }
184 | }
185 |
186 | # it makes no sense to have x but no y, or vice versa.
187 | if (array_key_exists('x', $params) && array_key_exists('y', $params)) {
188 | $opts['x'] = $params['x'];
189 | $opts['y'] = $params['y'];
190 | }
191 |
192 | return $opts;
193 | }
194 |
195 | /**
196 | * @param $action
197 | * @param $options
198 | *
199 | * @return array
200 | */
201 | public function addAction($action, $options)
202 | {
203 | $gesture = [
204 | 'action' => $action,
205 | 'options' => $options,
206 | ];
207 |
208 | $this->actions[] = $gesture;
209 |
210 | return $this->actions;
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/src/Traits/Touch.php:
--------------------------------------------------------------------------------
1 | getSessionUrl(), $this->getDriver());
21 | }
22 |
23 | /**
24 | * @return \Appium\TestCase\MultiAction
25 | */
26 | public function getMultiTouchAction()
27 | {
28 | return new MultiAction($this->getSessionUrl(), $this->getDriver());
29 | }
30 |
31 | /**
32 | * Swipe from one point to another point, for an optional duration.
33 | * convenience method added to Appium (NOT Selenium 3)
34 | *
35 | * @link https://pypkg.com/pypi/appium-python-client/f/appium/webdriver/webdriver.py
36 | *
37 | * @param string startX x-percent at which to start
38 | * @param string startY y-percent at which to start
39 | * @param string endX x-percent at which to end
40 | * @param string endY y-percent at which to end
41 | * @param int $duration (optional) time to take the swipe in ms
42 | *
43 | * @return mixed
44 | */
45 | public function swipe($startX, $startY, $endX, $endY, $duration = 800)
46 | {
47 | $action = $this->getTouchAction();
48 | $action->press(['x' => $startX, 'y' => $startY])
49 | ->wait($duration)
50 | ->moveTo(['x' => $endX, 'y' => $endY])
51 | ->wait($duration)
52 | ->release()
53 | ->perform();
54 |
55 | return $this;
56 | }
57 |
58 | /**
59 | * Flick from one point to another point.
60 | * convenience method added to Appium (NOT Selenium 3)
61 | *
62 | * @link https://pypkg.com/pypi/appium-python-client/f/appium/webdriver/webdriver.py
63 | *
64 | * @param string startX x-percent at which to start
65 | * @param string startY y-percent at which to start
66 | * @param string endX x-percent at which to end
67 | * @param string endY y-percent at which to end
68 | *
69 | * @return mixed
70 | */
71 | public function flickFromTo($startX, $startY, $endX, $endY)
72 | {
73 | $action = $this->getTouchAction();
74 | $action->press(['x' => $startX, 'y' => $startY])
75 | ->moveTo(['x' => $endX, 'y' => $endY])
76 | ->release()
77 | ->perform();
78 |
79 | return $this;
80 | }
81 |
82 | /**
83 | * Scrolls from one element to another
84 | * convenience method added to Appium (NOT Selenium 3)
85 | *
86 | * @link https://pypkg.com/pypi/appium-python-client/f/appium/webdriver/webdriver.py
87 | * @usage $this->scroll(['type'=>'id','value'=>'header_bar'],['type'=>'xpath','value'=>'div1[1]>classA>textare']);
88 | *
89 | * @param array $originElArray the element from which to being scrolling
90 | * @param array $destinationElArray the element to scroll to
91 | * @param int $duration
92 | *
93 | * @return $this
94 | */
95 | public function scroll($originElArray, $destinationElArray, $duration = 500)
96 | {
97 | $action = $this->getTouchAction();
98 | $action->press(['element' => $originElArray])
99 | ->wait($duration)
100 | ->moveTo(['element' => $destinationElArray])
101 | ->release()
102 | ->perform();
103 |
104 | return $this;
105 | }
106 |
107 | /**
108 | * Drag the origin element to the destination element
109 | * convenience method added to Appium (NOT Selenium 3)
110 | *
111 | * @link https://github.com/appium/python-client/blob/master/appium/webdriver/webdriver.py
112 | *
113 | * @param array $originElArray
114 | * @param array $destinationElArray
115 | * @param int $duration
116 | *
117 | * @return \Appium\Traits\Touch
118 | */
119 | public function dragAndDrop($originElArray, $destinationElArray, $duration = 500)
120 | {
121 | $action = $this->getTouchAction();
122 | $action->longPress(['element' => $originElArray])
123 | ->wait($duration)
124 | ->moveTo(['element' => $destinationElArray])
125 | ->release()
126 | ->perform();
127 |
128 | return $this;
129 | }
130 |
131 | /**
132 | * Taps on an particular place with up to five fingers, holding for a certain time
133 | * convenience method added to Appium (NOT Selenium 3)
134 | *
135 | * @link https://github.com/appium/python-client/blob/master/appium/webdriver/webdriver.py
136 | * @usage $this->tap([(100, 20), (100, 60), (100, 100)], 500);
137 | *
138 | * @param array $positions
139 | * @param int $duration
140 | *
141 | * @return \Appium\Traits\Touch
142 | */
143 | public function tap($positions, $duration = 500)
144 | {
145 | if (count($positions) == 1) {
146 | $action = $this->getTouchAction();
147 |
148 | $options = [
149 | 'x' => $positions[0][0],
150 | 'y' => $positions[0][1],
151 | ];
152 |
153 | if ($duration) {
154 | $options['duration'] = $duration;
155 | $action->longPress($options)->release()->perform();
156 | } else {
157 | $action->tap($options)->release()->perform();
158 | }
159 | } else {
160 | $multiTouchAction = $this->getMultiTouchAction();
161 | foreach ($positions as $position) {
162 | $action = $this->getTouchAction();
163 |
164 | $options = [
165 | 'x' => $position[0][0],
166 | 'y' => $position[0][1],
167 | ];
168 |
169 | if ($duration) {
170 | $options['duration'] = $duration;
171 | $action->longPress($options)->release()->perform();
172 | } else {
173 | $action->tap($options)->release()->perform();
174 | }
175 | $multiTouchAction->add($action);
176 | }
177 | $multiTouchAction->perform();
178 | }
179 |
180 | return $this;
181 | }
182 |
183 | /**
184 | * Pinch on an element a certain amount
185 | * convenience method added to Appium (NOT Selenium 3)
186 | *
187 | * @link https://github.com/appium/python-client/blob/master/appium/webdriver/webdriver.py
188 | * @usage $this->pinch($element)
189 | *
190 | * @param null $element the element to pinch
191 | * @param int $percent amount to pinch. Defaults to 200%
192 | * @param int $steps number of steps in the pinch action
193 | *
194 | * @return \Appium\Traits\Touch
195 | */
196 | public function pinch($element = null, $percent = 200, $steps = 50)
197 | {
198 | if ($element) {
199 | $element = $element['id'];
200 | }
201 |
202 | $options = [
203 | 'element' => $element,
204 | 'percent' => $percent,
205 | 'steps' => $steps,
206 | ];
207 |
208 | $this->execute([
209 | 'mobile: pinchClose',
210 | $options,
211 | ]);
212 |
213 | return $this;
214 | }
215 |
216 | /**
217 | * Pinch on an element a certain amount
218 | * convenience method added to Appium (NOT Selenium 3)
219 | *
220 | * @link https://github.com/appium/python-client/blob/master/appium/webdriver/webdriver.py
221 | * @usage $this->zoom($element)
222 | *
223 | * @param null $element the element to zoom
224 | * @param int $percent amount to pinch. Defaults to 200%
225 | * @param int $steps number of steps in the pinch action
226 | *
227 | * @return \Appium\Traits\Touch
228 | */
229 | public function zoom($element = null, $percent = 200, $steps = 50)
230 | {
231 | if ($element) {
232 | $element = $element['id'];
233 | }
234 |
235 | $options = [
236 | 'element' => $element,
237 | 'percent' => $percent,
238 | 'steps' => $steps,
239 | ];
240 |
241 | $this->execute([
242 | 'mobile: pinchOpen',
243 | $options,
244 | ]);
245 |
246 | return $this;
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | Appium Driver for Codeception
3 |
4 | Appium driver for codeception for writing mobile tests.
5 |
6 |
7 |
8 | [![Build Status][build-badge]][build]
9 | [![downloads][downloads-badge]][downloads]
10 | [![MIT License][license-badge]][license]
11 | [![Donate][donate-badge]][donate]
12 |
13 | [](#contributors)
14 | [![PRs Welcome][prs-badge]][prs]
15 | [![Code of Conduct][coc-badge]][coc]
16 | [![Watch on GitHub][github-watch-badge]][github-watch]
17 | [![Star on GitHub][github-star-badge]][github-star]
18 | [![Tweet][twitter-badge]][twitter]
19 |
20 | ## Requirement
21 |
22 | 1. PHP >= 7.0
23 | 2. [Appium](http://appium.io/)
24 | 3. [Inspect App with Appium Desktop](https://medium.com/@eliasnogueira/inspect-an-app-with-the-new-appium-desktop-8ce4dc9aa95c)
25 | 4. Devices:
26 | * **Android**
27 | * [Setup Android SDK on Mac](https://gist.github.com/agrcrobles/165ac477a9ee51198f4a870c723cd441)
28 | * **iOS**
29 | * Install Xcode from the following [link](https://developer.apple.com/xcode/) or run the following command
30 | inside your terminal:
31 | ```bash
32 | xcode-select --install
33 | ```
34 | * Install the Carthage dependency manager:
35 | ```bash
36 | brew install carthage
37 | ```
38 |
39 | ## Table of Contents
40 |
41 | * [Install](#install)
42 | * [Tests](#tests)
43 | * [Writing tests for Android](#writing-tests-for-android)
44 | * [Writing tests for iOS](#writing-tests-for-ios)
45 | * [Generating Actor classes](#generating-actor-classes)
46 | * [Your First Android Test](#your-first-android-test)
47 | * [Your First iOS Test](#your-first-ios-test)
48 | * [Running tests](#running-tests)
49 |
50 | ## Install
51 |
52 | Just add `me-io/appium-driver-codeception` to your project's composer.json file:
53 |
54 | ```json
55 | {
56 | "require": {
57 | "me-io/appium-driver-codeception": "~1"
58 | }
59 | }
60 | ```
61 |
62 | and then run `composer install`. This will install codeception appium driver and all it's dependencies. Or run the following command
63 |
64 | ```bash
65 | composer require me-io/appium-driver-codeception
66 | ```
67 |
68 | ## Tests
69 |
70 | Now lets run the following command at the root directory of your project:
71 |
72 | ```bash
73 | codecept bootstrap
74 | ```
75 |
76 | This command will creates a configuration file for codeception and tests directory and default test suites.
77 |
78 | ### Writing tests for Android
79 |
80 | Now, lets create a new configuration file `android.suite.yml` inside tests directory and put the following contents inside of it.
81 |
82 | ```yml
83 | class_name: AndroidGuy
84 | modules:
85 | enabled:
86 | # Enable appium driver
87 | - \Appium\AppiumDriver
88 | - Asserts
89 | config:
90 | # Configuration for appium driver
91 | \Appium\AppiumDriver:
92 | host: 0.0.0.0
93 | port: 4723
94 | dummyRemote: false
95 | resetAfterSuite: true
96 | resetAfterCest: false
97 | resetAfterTest: false
98 | resetAfterStep: false
99 | capabilities:
100 | platformName: 'Android'
101 | deviceName: 'Android device'
102 | automationName: 'Appium'
103 | appPackage: io.selendroid.testapp
104 | fullReset: false
105 | noReset: false
106 | newCommandTimeout: 7200
107 | nativeInstrumentsLib: true
108 | connection_timeout: 500
109 | request_timeout: 500
110 | autoAcceptAlerts: true
111 | appActivity: io.selendroid.testapp.HomeScreenActivity
112 | skipUnlock: true
113 | ```
114 |
115 | > **Note**: `deviceName` should be set as `Android device` only for real device. For Android Emulator use the name of the virtual device.
116 |
117 |
118 | ### Writing tests for iOS
119 |
120 | Now, lets create a new configuration file `ios.suite.yml` inside tests directory and put the following contents inside of it.
121 |
122 | ```yml
123 | class_name: IosGuy
124 | modules:
125 | enabled:
126 | # Enable appium driver
127 | - \Appium\AppiumDriver
128 | - Asserts
129 | config:
130 | # Configuration for appium driver
131 | \Appium\AppiumDriver:
132 | host: 0.0.0.0
133 | port: 4723
134 | dummyRemote: false
135 | resetAfterSuite: true
136 | resetAfterCest: false
137 | resetAfterTest: false
138 | resetAfterStep: false
139 | capabilities:
140 | # PATH OF YOUR APP (something like /Users/username/Documents/ios.app)
141 | app: ''
142 | # xcideOrgId is Apple developer team identifier string.
143 | xcodeOrgId: ''
144 | # xcodeSigningId is a string representing a signing certificate. iPhone Developer by default.
145 | xcodeSigningId: 'iPhone Developer'
146 | platformName: 'iOS'
147 | platformVersion: '11.2'
148 | deviceName: 'iPhone8'
149 | # Your device udid
150 | udid: ''
151 | useNewWDA: false
152 | newCommandTimeout: 7200
153 | automationName: 'XCUITest'
154 | autoAcceptAlerts: true
155 | fullReset: false
156 | noReset: true
157 | nativeInstrumentsLib: true
158 | connection_timeout: 500
159 | request_timeout: 500
160 | skipUnlock: true
161 | clearSystemFiles: true
162 | showIOSLog: true
163 | ```
164 |
165 | ### Generating Actor classes
166 |
167 | Now we need to generate actor class for the `AndroidGuy`/`IosGuy` that we defined in `android.suite.yml`/`ios.suite.yml`. To generate the actor class for `AndroidGuy`/`IosGuy` run the following command inside your terminal:
168 |
169 | ```bash
170 | codecept build
171 | ```
172 |
173 | ### Your First Android Test
174 |
175 | To create your first android test create a new directory `android` inside `tests` folder. After creating the `android` folder create a new file `FirstAndroidCest.php` and put the following contents inside of it:
176 |
177 | ```php
178 | class FirstAndroidCest
179 | {
180 | public function changeLanguage(AndroidGuy $I)
181 | {
182 | $I->implicitWait([
183 | 'ms' => 3500,
184 | ]);
185 | $text = $I->byId('id_of_button')->getText();
186 | $I->assertEquals('Hello, World!', $text);
187 | }
188 | }
189 | ```
190 |
191 | ### Your First iOS Test
192 |
193 | To create your first iOS test create a new directory `ios` inside `tests` folder. After creating the `ios` directory create a new file `FirstIosCest.php` and put the following contents inside of it:
194 |
195 | ```php
196 | class FirstIosCest
197 | {
198 | public function lockPhone(Ios $I)
199 | {
200 | $I->implicitWait([
201 | 'ms' => 10000,
202 | ]);
203 | $I->assertEquals('Hello, World!', 'Hello, World!');
204 | $I->amGoingTo("lock phone");
205 | $I->lock([null]);
206 | }
207 | }
208 | ```
209 |
210 | ### Running tests
211 |
212 | Run the appium server by running the following command:
213 |
214 | ```bash
215 | appium
216 | ```
217 | > **NOTE:** If you want to change IP/Port run the appium command like this:
218 | ```
219 | appium -a -p
220 | ```
221 |
222 | After running the appium server now you need to start android emulator and install the application that you want to test. If you don't know how to start the emulator you can follow the following guide [Setup Genymotion Android Emulators on Mac OS
223 | ](https://shankargarg.wordpress.com/2016/02/25/setup-genymotion-android-emulators-on-mac-os/)
224 |
225 | Now run the following command inside your terminal to run the tests:
226 |
227 | ```bash
228 | # For Android
229 | codecept run android FirstAndroidCest.php --steps
230 |
231 | # For iOS
232 | codecept run ios FirstIosCest.php --steps
233 | ```
234 |
235 | > **Note**: While following the steps that are mentioned here if you get `codecept command not found` error try to run `codecept` command like this `./vendor/bin/codecept`.
236 |
237 | ## Contributors
238 |
239 | A huge thanks to all of our contributors:
240 |
241 |
242 |
243 | | [
Mohamed Meabed](https://github.com/Meabed)
[💻](https://github.com/me-io/appium-driver-codeception/commits?author=Meabed "Code") [📢](#talk-Meabed "Talks") | [
Zeeshan Ahmad](https://github.com/ziishaned)
[💻](https://github.com/me-io/appium-driver-codeception/commits?author=ziishaned "Code") [🐛](https://github.com/me-io/appium-driver-codeception/issues?q=author%3Aziishaned "Bug reports") [⚠️](https://github.com/me-io/appium-driver-codeception/commits?author=ziishaned "Tests") [📖](https://github.com/me-io/appium-driver-codeception/commits?author=ziishaned "Documentation") |
244 | | :---: | :---: |
245 |
246 |
247 |
248 | ## License
249 |
250 | The code is available under the [MIT license](LICENSE.md).
251 |
252 | [build-badge]: https://img.shields.io/travis/me-io/appium-driver-codeception.svg?style=flat-square
253 | [build]: https://travis-ci.org/me-io/appium-driver-codeception
254 | [downloads-badge]: https://img.shields.io/packagist/dm/me-io/appium-driver-codeception.svg?style=flat-square
255 | [downloads]: https://packagist.org/packages/me-io/appium-driver-codeception/stats
256 | [license-badge]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
257 | [license]: https://github.com/me-io/appium-driver-codeception/blob/master/LICENSE.md
258 | [prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
259 | [prs]: http://makeapullrequest.com
260 | [coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
261 | [coc]: https://github.com/me-io/appium-driver-codeception/blob/master/CODE_OF_CONDUCT.md
262 | [github-watch-badge]: https://img.shields.io/github/watchers/me-io/appium-driver-codeception.svg?style=social
263 | [github-watch]: https://github.com/me-io/appium-driver-codeception/watchers
264 | [github-star-badge]: https://img.shields.io/github/stars/me-io/appium-driver-codeception.svg?style=social
265 | [github-star]: https://github.com/me-io/appium-driver-codeception/stargazers
266 | [twitter]: https://twitter.com/intent/tweet?text=Check%20out%20appium-driver-codeception!%20https://github.com/me-io/appium-driver-codeception%20%F0%9F%91%8D
267 | [twitter-badge]: https://img.shields.io/twitter/url/https/github.com/me-io/appium-driver-codeception.svg?style=social
268 | [donate-badge]: https://img.shields.io/badge/paypal-donate-179BD7.svg?style=flat-squares
269 | [donate]: https://www.paypal.me/meabed
270 |
--------------------------------------------------------------------------------
/cmd/Parser/Json/jsonwire-full.json:
--------------------------------------------------------------------------------
1 | {
2 | "GET /status": "Query the server's current status.",
3 | "POST /session": "Create a new session.",
4 | "GET /sessions": "Returns a list of the currently active sessions.",
5 | "GET /session/:sessionId": "Retrieve the capabilities of the specified session.",
6 | "DELETE /session/:sessionId": "Delete the session.",
7 | "POST /session/:sessionId/timeouts": "Configure the amount of time that a particular type of operation can execute for before they are aborted and a |Timeout| error is returned to the client.",
8 | "POST /session/:sessionId/timeouts/async_script": "Set the amount of time, in milliseconds, that asynchronous scripts executed by /session/:sessionId/execute_async are permitted to run before they are aborted and a |Timeout| error is returned to the client.",
9 | "POST /session/:sessionId/timeouts/implicit_wait": "Set the amount of time the driver should wait when searching for elements.",
10 | "GET /session/:sessionId/window_handle": "Retrieve the current window handle.",
11 | "GET /session/:sessionId/window_handles": "Retrieve the list of all window handles available to the session.",
12 | "GET /session/:sessionId/url": "Retrieve the URL of the current page.",
13 | "POST /session/:sessionId/url": "Navigate to a new URL.",
14 | "POST /session/:sessionId/forward": "Navigate forwards in the browser history, if possible.",
15 | "POST /session/:sessionId/back": "Navigate backwards in the browser history, if possible.",
16 | "POST /session/:sessionId/refresh": "Refresh the current page.",
17 | "POST /session/:sessionId/execute": "Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame.",
18 | "POST /session/:sessionId/execute_async": "Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame.",
19 | "GET /session/:sessionId/screenshot": "Take a screenshot of the current page.",
20 | "GET /session/:sessionId/ime/available_engines": "List all available engines on the machine.",
21 | "GET /session/:sessionId/ime/active_engine": "Get the name of the active IME engine.",
22 | "GET /session/:sessionId/ime/activated": "Indicates whether IME input is active at the moment (not if it's available).",
23 | "POST /session/:sessionId/ime/deactivate": "De-activates the currently-active IME engine.",
24 | "POST /session/:sessionId/ime/activate": "Make an engines that is available (appears on the listreturned by getAvailableEngines) active.",
25 | "POST /session/:sessionId/frame": "Change focus to another frame on the page.",
26 | "POST /session/:sessionId/window": "Change focus to another window.",
27 | "DELETE /session/:sessionId/window": "Close the current window.",
28 | "POST /session/:sessionId/window/:windowHandle/size": "Change the size of the specified window.",
29 | "GET /session/:sessionId/window/:windowHandle/size": "Get the size of the specified window.",
30 | "POST /session/:sessionId/window/:windowHandle/position": "Change the position of the specified window.",
31 | "GET /session/:sessionId/window/:windowHandle/position": "Get the position of the specified window.",
32 | "POST /session/:sessionId/window/:windowHandle/maximize": "Maximize the specified window if not already maximized.",
33 | "GET /session/:sessionId/cookie": "Retrieve all cookies visible to the current page.",
34 | "POST /session/:sessionId/cookie": "Set a cookie.",
35 | "DELETE /session/:sessionId/cookie": "Delete all cookies visible to the current page.",
36 | "DELETE /session/:sessionId/cookie/:name": "Delete the cookie with the given name.",
37 | "GET /session/:sessionId/source": "Get the current page source.",
38 | "GET /session/:sessionId/title": "Get the current page title.",
39 | "POST /session/:sessionId/element": "Search for an element on the page, starting from the document root.",
40 | "POST /session/:sessionId/elements": "Search for multiple elements on the page, starting from the document root.",
41 | "POST /session/:sessionId/element/active": "Get the element on the page that currently has focus.",
42 | "GET /session/:sessionId/element/:id": "Describe the identified element.",
43 | "POST /session/:sessionId/element/:id/element": "Search for an element on the page, starting from the identified element.",
44 | "POST /session/:sessionId/element/:id/elements": "Search for multiple elements on the page, starting from the identified element.",
45 | "POST /session/:sessionId/element/:id/click": "Click on an element.",
46 | "POST /session/:sessionId/element/:id/submit": "Submit a FORM element.",
47 | "GET /session/:sessionId/element/:id/text": "Returns the visible text for the element.",
48 | "POST /session/:sessionId/element/:id/value": "Send a sequence of key strokes to an element.",
49 | "POST /session/:sessionId/keys": "Send a sequence of key strokes to the active element.",
50 | "GET /session/:sessionId/element/:id/name": "Query for an element's tag name.",
51 | "POST /session/:sessionId/element/:id/clear": "Clear a TEXTAREA or text INPUT element's value.",
52 | "GET /session/:sessionId/element/:id/selected": "Determine if an OPTION element, or an INPUT element of type checkbox or radiobutton is currently selected.",
53 | "GET /session/:sessionId/element/:id/enabled": "Determine if an element is currently enabled.",
54 | "GET /session/:sessionId/element/:id/attribute/:name": "Get the value of an element's attribute.",
55 | "GET /session/:sessionId/element/:id/equals/:other": "Test if two element IDs refer to the same DOM element.",
56 | "GET /session/:sessionId/element/:id/displayed": "Determine if an element is currently displayed.",
57 | "GET /session/:sessionId/element/:id/location": "Determine an element's location on the page.",
58 | "GET /session/:sessionId/element/:id/location_in_view": "Determine an element's location on the screen once it has been scrolled into view.",
59 | "GET /session/:sessionId/element/:id/size": "Determine an element's size in pixels.",
60 | "GET /session/:sessionId/element/:id/css/:propertyName": "Query the value of an element's computed CSS property.",
61 | "GET /session/:sessionId/orientation": "Get the current browser orientation.",
62 | "POST /session/:sessionId/orientation": "Set the browser orientation.",
63 | "GET /session/:sessionId/alert_text": "Gets the text of the currently displayed JavaScript alert(), confirm(), or prompt() dialog.",
64 | "POST /session/:sessionId/alert_text": "Sends keystrokes to a JavaScript prompt() dialog.",
65 | "POST /session/:sessionId/accept_alert": "Accepts the currently displayed alert dialog.",
66 | "POST /session/:sessionId/dismiss_alert": "Dismisses the currently displayed alert dialog.",
67 | "POST /session/:sessionId/moveto": "Move the mouse by an offset of the specificed element.",
68 | "POST /session/:sessionId/click": "Click any mouse button (at the coordinates set by the last moveto command).",
69 | "POST /session/:sessionId/buttondown": "Click and hold the left mouse button (at the coordinates set by the last moveto command).",
70 | "POST /session/:sessionId/buttonup": "Releases the mouse button previously held (where the mouse is currently at).",
71 | "POST /session/:sessionId/doubleclick": "Double-clicks at the current mouse coordinates (set by moveto).",
72 | "POST /session/:sessionId/touch/click": "Single tap on the touch enabled device.",
73 | "POST /session/:sessionId/touch/down": "Finger down on the screen.",
74 | "POST /session/:sessionId/touch/up": "Finger up on the screen.",
75 | "POST /session/:sessionId/touch/move": "Finger move on the screen.",
76 | "POST /session/:sessionId/touch/scroll": "Scroll on the touch screen using finger based motion events.",
77 | "POST /session/:sessionId/touch/doubleclick": "Double tap on the touch screen using finger motion events.",
78 | "POST /session/:sessionId/touch/longclick": "Long press on the touch screen using finger motion events.",
79 | "POST /session/:sessionId/touch/flick": "Flick on the touch screen using finger motion events.",
80 | "GET /session/:sessionId/location": "Get the current geo location.",
81 | "POST /session/:sessionId/location": "Set the current geo location.",
82 | "GET /session/:sessionId/local_storage": "Get all keys of the storage.",
83 | "POST /session/:sessionId/local_storage": "Set the storage item for the given key.",
84 | "DELETE /session/:sessionId/local_storage": "Clear the storage.",
85 | "GET /session/:sessionId/local_storage/key/:key": "Get the storage item for the given key.",
86 | "DELETE /session/:sessionId/local_storage/key/:key": "Remove the storage item for the given key.",
87 | "GET /session/:sessionId/local_storage/size": "Get the number of items in the storage.",
88 | "GET /session/:sessionId/session_storage": "Get all keys of the storage.",
89 | "POST /session/:sessionId/session_storage": "Set the storage item for the given key.",
90 | "DELETE /session/:sessionId/session_storage": "Clear the storage.",
91 | "GET /session/:sessionId/session_storage/key/:key": "Get the storage item for the given key.",
92 | "DELETE /session/:sessionId/session_storage/key/:key": "Remove the storage item for the given key.",
93 | "GET /session/:sessionId/session_storage/size": "Get the number of items in the storage.",
94 | "POST /session/:sessionId/log": "Get the log for a given log type.",
95 | "GET /session/:sessionId/log/types": "Get available log types.",
96 | "GET /session/:sessionId/application_cache/status": "Get the status of the html5 application cache.",
97 | "GET /session/:sessionId/context": "Get the current context (mjsonWire).",
98 | "POST /session/:sessionId/context": "Set the current context (mjsonWire).",
99 | "GET /session/:sessionId/contexts": "Get a list of the available contexts (mjsonWire).",
100 | "POST /session/:sessionId/touch/perform": "Perform touch action (mjsonWire).",
101 | "POST /session/:sessionId/touch/multi/perform": "Perform multitouch action (mjsonWire).",
102 | "POST /session/:sessionId/appium/device/shake": "Shake device (mjsonWire).",
103 | "POST /session/:sessionId/appium/device/lock": "Lock device (mjsonWire).",
104 | "POST /session/:sessionId/appium/device/keyevent": "Send key event to device (DEPRECATED) (mjsonWire).",
105 | "POST /session/:sessionId/appium/device/press_keycode": "Send key event to device (mjsonWire).",
106 | "POST /session/:sessionId/appium/device/rotate": "Rotate device (mjsonWire).",
107 | "GET /session/:sessionId/appium/device/current_activity": "Get current activity (mjsonWire).",
108 | "GET /session/:sessionId/appium/device/current_package": "Get current package (mjsonWire).",
109 | "POST /session/:sessionId/appium/device/install_app": "Install app (mjsonWire).",
110 | "POST /session/:sessionId/appium/device/remove_app": "Remove app (mjsonWire).",
111 | "POST /session/:sessionId/appium/device/app_installed": "Check if the app is installed (mjsonWire).",
112 | "POST /session/:sessionId/appium/device/push_file": "Push file to device (mjsonWire).",
113 | "POST /session/:sessionId/appium/device/pull_file": "Pull file from device (mjsonWire).",
114 | "POST /session/:sessionId/appium/device/pull_folder": "Pull folder from device (mjsonWire).",
115 | "POST /session/:sessionId/appium/device/toggle_airplane_mode": "Toggle airplane mode (mjsonWire).",
116 | "POST /session/:sessionId/appium/device/toggle_wifi": "Toggle wifi (mjsonWire).",
117 | "POST /session/:sessionId/appium/device/toggle_location_services": "Toggle location services (mjsonWire).",
118 | "POST /session/:sessionId/appium/device/toggle_data": "Toggle data (mjsonWire).",
119 | "POST /session/:sessionId/appium/device/start_activity": "Start an Android activity (mjsonWire).",
120 | "POST /session/:sessionId/appium/app/launch": "Launch app (mjsonWire).",
121 | "POST /session/:sessionId/appium/app/close": "Close app (mjsonWire).",
122 | "POST /session/:sessionId/appium/app/reset": "Reset app (mjsonWire).",
123 | "POST /session/:sessionId/appium/app/background": "Background app (mjsonWire).",
124 | "POST /session/:sessionId/appium/app/end_test_coverage": "End test coverage (mjsonWire).",
125 | "POST /session/:sessionId/appium/app/complex_find": "Find within app (mjsonWire).",
126 | "POST /session/:sessionId/appium/app/strings": "Retrieve app strings (mjsonWire).",
127 | "POST /session/:sessionId/appium/element/:elementId?/value": "Set element immediate value (mjsonWire).",
128 | "GET /session/:sessionId/network_connection": "Get appium selendroid network connection type (mjsonWire).",
129 | "POST /session/:sessionId/network_connection": "Set appium selendroid network connection type (mjsonWire).",
130 | "POST /session/:sessionId/appium/device/hide_keyboard": "Hide keyboard (mjsonWire).",
131 | "POST /session/:sessionId/appium/device/open_notifications": "Open Notifications (mjsonWire).",
132 | "POST /session/:sessionId/appium/device/finger_print": "Send fingerprint (mjsonWire).",
133 | "POST /session/:sessionId/appium/device/send_sms": "Send sms to Android emulator (mjsonWire).",
134 | "POST /session/:sessionId/appium/device/gsm_call": "Send GSM call to Android emulator (mjsonWire).",
135 | "POST /session/:sessionId/appium/device/gsm_signal": "Set GSM signal strenght on Android emulator (mjsonWire).",
136 | "POST /session/:sessionId/appium/device/gsm_voice": "Set GSM state fingerprint (mjsonWire).",
137 | "POST /session/:sessionId/appium/device/power_capacity": "Set battery percent on Android emulator (mjsonWire).",
138 | "POST /session/:sessionId/appium/device/power_ac": "Set state of power charger on Android emulator(mjsonWire).",
139 | "POST /session/:sessionId/appium/device/network_speed": "Set Android emulator network speed (mjsonWire).",
140 | "POST /session/:sessionId/simulator/touch_id": "Simulate iOS touchID (mjsonWire)"
141 | }
142 |
--------------------------------------------------------------------------------
/src/AppiumDriver.php:
--------------------------------------------------------------------------------
1 | getModule('AppiumDriver')->AppiumDriver->getKeyboard()->sendKeys('hello, AppiumDriver');
33 | * ```
34 | */
35 | class AppiumDriver extends CodeceptionModule implements
36 | MultiSessionInterface,
37 | ScreenshotSaver,
38 | RequiresPackage
39 | {
40 | use BaseCommands;
41 | use Touch;
42 | use Key;
43 | use Elm;
44 | use Util;
45 |
46 | protected $requiredFields = ['host'];
47 | protected $config
48 | = [
49 | 'host' => '127.0.0.1',
50 | 'port' => '4723',
51 | 'resetAfterSuite' => true,
52 | 'resetAfterCest' => true,
53 | 'resetAfterStep' => false,
54 | 'resetAfterTest' => false,
55 | 'capabilities' => [],
56 | 'connection_timeout' => null,
57 | 'request_timeout' => null,
58 | 'http_proxy' => null,
59 | 'http_proxy_port' => null,
60 | 'ssl_proxy' => null,
61 | 'ssl_proxy_port' => null,
62 | 'debug_log_entries' => 15,
63 | ];
64 |
65 | protected $wd_host;
66 | /** @var \PHPUnit_Extensions_Selenium2TestCase_URL */
67 | protected $selenium_url;
68 | protected $capabilities;
69 | protected $connectionTimeoutInMs;
70 | protected $requestTimeoutInMs;
71 | protected $test;
72 | protected $sessionSnapshots = [];
73 | protected $sessions = [];
74 | protected $httpProxy;
75 | protected $httpProxyPort;
76 | protected $sslProxy;
77 | protected $sslProxyPort;
78 |
79 |
80 | /**
81 | * @var AppiumRemoteDriver
82 | */
83 | public $AppiumDriver;
84 | /**
85 | * @var Session
86 | */
87 | public $AppiumSession;
88 |
89 | /**
90 | * @var array
91 | */
92 | protected $classes = [];
93 |
94 | /**
95 | * @return array
96 | */
97 | public function _requires()
98 | {
99 | return [];
100 | }
101 |
102 | /**
103 | *
104 | */
105 | public function _initialize()
106 | {
107 | $this->wd_host = sprintf('http://%s:%s/wd/hub', $this->config['host'], $this->config['port']);
108 | $this->selenium_url = new \PHPUnit_Extensions_Selenium2TestCase_URL(sprintf('http://%s:%s', $this->config['host'], $this->config['port']));
109 | $this->capabilities = $this->config['capabilities'];
110 | $this->outputCli("Snapshot Saved session snapshot");
111 |
112 | $this->connectionTimeoutInMs = $this->config['connection_timeout'] * 1000;
113 | $this->requestTimeoutInMs = $this->config['request_timeout'] * 1000;
114 | try {
115 | if (!empty($this->config['dummyRemote'])) {
116 | $this->AppiumDriver = new Dummy();
117 | } else {
118 | $this->AppiumDriver = new AppiumRemoteDriver($this->selenium_url, $this->connectionTimeoutInMs);
119 | $this->AppiumSession = $this->AppiumDriver->startSession($this->capabilities, $this->selenium_url);
120 | }
121 |
122 | $this->sessions[] = $this->_backupSession();
123 | } catch (\Exception $e) {
124 | throw new ConnectionException(
125 | $e->getMessage() . "\n \nPlease make sure that Selenium Server or PhantomJS is running."
126 | );
127 | }
128 | }
129 |
130 | /**
131 | * @param TestInterface $test
132 | */
133 | public function _before(TestInterface $test)
134 | {
135 | $file = $test->getMetadata()->getFilename();
136 | $class = $this->getClassNames($file)[0];
137 | $classMd5 = $class;
138 |
139 | if ($this->config['resetAfterCest'] && !key_exists($classMd5, $this->classes)) {
140 | $this->classes[$classMd5] = $class;
141 |
142 | if (count($this->classes) > 1) {
143 | $this->outputCli('Cleaning appium: before ' . $class);
144 | $this->cleanAppiumDriver();
145 | }
146 | }
147 |
148 | if (!isset($this->AppiumSession)) {
149 | $this->_initialize();
150 | }
151 | $test->getMetadata()->setCurrent([
152 | 'capabilities' => $this->config['capabilities'],
153 | ]);
154 | }
155 |
156 | /**
157 | * @param TestInterface $test
158 | */
159 | public function _after(TestInterface $test)
160 | {
161 |
162 | if ($this->config['resetAfterTest']) {
163 | $this->outputCli('Cleaning appium: after ' . $test->getMetadata()->getName());
164 | $this->cleanAppiumDriver();
165 |
166 | return;
167 | }
168 | }
169 |
170 | /**
171 | * @param Step $step
172 | */
173 | public function _afterStep(Step $step)
174 | {
175 | // this is just to make sure AppiumDriver is cleared after suite
176 | if ($this->config['resetAfterStep']) {
177 | $this->outputCli('Cleaning appium: after ' . $step->getAction());
178 | $this->cleanAppiumDriver();
179 | }
180 | }
181 |
182 | /**
183 | *
184 | */
185 | public function _afterSuite()
186 | {
187 | // this is just to make sure AppiumDriver is cleared after suite
188 | if ($this->config['resetAfterSuite']) {
189 | $this->outputCli('Cleaning appium: after suite');
190 | $this->cleanAppiumDriver();
191 | }
192 | }
193 |
194 | /**
195 | * @param TestInterface $test
196 | * @param \Exception $fail
197 | */
198 | public function _failed(TestInterface $test, $fail)
199 | {
200 | // todo from appium logs
201 | //$this->debugAppiumDriverLogs();
202 | $filename = preg_replace('~\W~', '.', Descriptor::getTestSignature($test));
203 | $outputDir = codecept_output_dir();
204 | $this->_saveScreenshot($report = $outputDir . mb_strcut($filename, 0, 245, 'utf-8') . '.fail.png');
205 | $test->getMetadata()->addReport('png', $report);
206 | $this->debug("Screenshot is saved into '$outputDir' dir");
207 | }
208 |
209 | /**
210 | * Print out latest Selenium Logs in debug mode
211 | */
212 | public function debugAppiumDriverLogs()
213 | {
214 | // todo implement
215 | }
216 |
217 | /**
218 | * Turns an array of log entries into a human-readable string.
219 | * Each log entry is an array with the keys "timestamp", "level", and "message".
220 | * See https://code.google.com/p/selenium/wiki/JsonWireProtocol#Log_Entry_JSON_Object
221 | *
222 | * @param array $logEntries
223 | *
224 | * @return string
225 | */
226 | protected function formatLogEntries(array $logEntries)
227 | {
228 | $formattedLogs = '';
229 |
230 | foreach ($logEntries as $logEntry) {
231 | // Timestamp is in milliseconds, but date() requires seconds.
232 | $time = date('H:i:s', $logEntry['timestamp'] / 1000) .
233 | // Append the milliseconds to the end of the time string
234 | '.' . ($logEntry['timestamp'] % 1000);
235 | $formattedLogs .= "{$time} {$logEntry['level']} - {$logEntry['message']}\n";
236 | }
237 |
238 | return $formattedLogs;
239 | }
240 |
241 | /**
242 | * clean appium session
243 | */
244 | protected function cleanAppiumDriver()
245 | {
246 | foreach ($this->sessions as $session) {
247 | $this->_loadSession($session);
248 | try {
249 | $this->AppiumSession->stop();
250 | } catch (\Exception $e) {
251 | // Session already closed so nothing to do
252 | }
253 | unset($this->AppiumSession);
254 | }
255 | $this->sessions = [];
256 | }
257 |
258 | /**
259 | * @return array|null
260 | */
261 | protected function getProxy()
262 | {
263 | $proxyConfig = [];
264 | if ($this->config['http_proxy']) {
265 | $proxyConfig['httpProxy'] = $this->config['http_proxy'];
266 | if ($this->config['http_proxy_port']) {
267 | $proxyConfig['httpProxy'] .= ':' . $this->config['http_proxy_port'];
268 | }
269 | }
270 | if ($this->config['ssl_proxy']) {
271 | $proxyConfig['sslProxy'] = $this->config['ssl_proxy'];
272 | if ($this->config['ssl_proxy_port']) {
273 | $proxyConfig['sslProxy'] .= ':' . $this->config['ssl_proxy_port'];
274 | }
275 | }
276 | if (!empty($proxyConfig)) {
277 | $proxyConfig['proxyType'] = 'manual';
278 |
279 | return $proxyConfig;
280 | }
281 |
282 | return null;
283 | }
284 |
285 | /**
286 | * @return string|null
287 | */
288 | public function getDeviceName()
289 | {
290 | $cap = $this->config['capabilities'];
291 | return isset($cap['deviceName']) ? $cap['deviceName'] : '';
292 | }
293 |
294 | /**
295 | *
296 | */
297 | public function _initializeSession()
298 | {
299 | $this->AppiumDriver = new AppiumRemoteDriver($this->selenium_url, $this->connectionTimeoutInMs);
300 | $this->AppiumSession = $this->AppiumDriver->startSession($this->capabilities, $this->selenium_url);
301 | $this->sessions[] = $this->_backupSession();
302 | }
303 |
304 | /**
305 | * @param $session
306 | */
307 | public function _loadSession($session)
308 | {
309 | $this->AppiumSession = $session;
310 | }
311 |
312 | /**
313 | * @param $filename
314 | */
315 | public function _saveScreenshot($filename)
316 | {
317 | if ($this->AppiumSession !== null) {
318 | $this->takeScreenshotAndSave($filename);
319 | } else {
320 | codecept_debug('AppiumDriver::_saveScreenshot method has been called when AppiumDriver is not set');
321 | codecept_debug(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
322 | }
323 | }
324 |
325 | /**
326 | * @return Session
327 | */
328 | public function _backupSession()
329 | {
330 | return $this->AppiumSession;
331 | }
332 |
333 | /**
334 | * @param Session $AppiumSession
335 | */
336 | public function _closeSession($AppiumSession = null)
337 | {
338 | $keys = array_keys($this->sessions, $AppiumSession, true);
339 | $key = array_shift($keys);
340 | try {
341 | $AppiumSession->stop();
342 | } catch (\Exception $e) {
343 | // Session already closed so nothing to do
344 | }
345 | unset($this->sessions[$key]);
346 | }
347 |
348 | /**
349 | * @return \Appium\Remote\AppiumRemoteDriver
350 | */
351 | public function getDriver()
352 | {
353 | return $this->AppiumDriver;
354 | }
355 |
356 | /**
357 | * @return \PHPUnit_Extensions_Selenium2TestCase_URL
358 | */
359 | public function getSessionUrl()
360 | {
361 | return $this->getSession()->getSessionUrl();
362 | }
363 |
364 | /**
365 | * @return \Appium\TestCase\Session
366 | */
367 | public function getSession()
368 | {
369 | return $this->AppiumSession;
370 | }
371 |
372 | /**
373 | * get class names from php file
374 | *
375 | * @param $file
376 | *
377 | * @return array
378 | */
379 | protected function getClassNames($file)
380 | {
381 | $php_code = file_get_contents($file);
382 | $classes = [];
383 | $namespace = "";
384 | $tokens = token_get_all($php_code);
385 | $count = count($tokens);
386 |
387 | for ($i = 0; $i < $count; $i++) {
388 | if ($tokens[$i][0] === T_NAMESPACE) {
389 | for ($j = $i + 1; $j < $count; ++$j) {
390 | if ($tokens[$j][0] === T_STRING) {
391 | $namespace .= "\\" . $tokens[$j][1];
392 | } elseif ($tokens[$j] === '{' or $tokens[$j] === ';') {
393 | break;
394 | }
395 | }
396 | }
397 | if ($tokens[$i][0] === T_CLASS) {
398 | for ($j = $i + 1; $j < $count; ++$j) {
399 | if ($tokens[$j] === '{') {
400 | $classes[] = $namespace . "\\" . $tokens[$i + 2][1];
401 | }
402 | }
403 | }
404 | }
405 |
406 | return $classes;
407 | }
408 |
409 | /**
410 | * print to cli
411 | *
412 | * @param $msg
413 | */
414 | public function outputCli($msg)
415 | {
416 | $output = new Output([]);
417 | $output->writeln('');
418 | $output->writeln($msg);
419 | $output->writeln('');
420 | }
421 |
422 | //// ___ _ ___ __ __ ___ _ _ _____ ___
423 | //// | __| | | __| \/ | __| \| |_ _/ __|
424 | //// | _|| |__| _|| |\/| | _|| .` | | | \__ \
425 | //// |___|____|___|_| |_|___|_|\_| |_| |___/
426 | ////
427 |
428 | /**
429 | * @return \Appium\TestCase\Element
430 | */
431 | public function TestCaseElement()
432 | {
433 | return new Element($this->AppiumDriver, $this->getSessionUrl());
434 | }
435 |
436 |
437 | //// ___ ___ __ __ __ __ _ _ _ ___ ___
438 | //// / __/ _ \| \/ | \/ | /_\ | \| | \/ __|
439 | //// | (_| (_) | |\/| | |\/| |/ _ \| .` | |) \__ \
440 | //// \___\___/|_| |_|_| |_/_/ \_\_|\_|___/|___/
441 | ////
442 |
443 | const POST = 'POST';
444 | const GET = 'GET';
445 | const DEL = 'DELETE';
446 |
447 | /**
448 | * @param $method
449 | * @param $command
450 | * @param $data
451 | *
452 | * @return mixed
453 | */
454 | public function driverCommand($method = 'POST', $command, $data = [])
455 | {
456 |
457 | $url = $this->getSession()->getSessionUrl()->descend($command);
458 |
459 | /** @var \PHPUnit_Extensions_Selenium2TestCase_Response $response */
460 | $response = $this->getDriver()->curl($method, $url, $data);
461 |
462 | return $response->getValue();
463 | }
464 |
465 | /**
466 | * @param $method
467 | * @param $command
468 | * @param $data
469 | *
470 | * @return mixed
471 | */
472 | public function driverCommandWithoutSession($method = 'POST', $command, $data = [])
473 | {
474 |
475 | $url = $this->getSession()->getSessionUrl()->descend($command);
476 |
477 | /** @var \PHPUnit_Extensions_Selenium2TestCase_Response $response */
478 | $response = $this->getDriver()->curl($method, $url, $data);
479 |
480 | return $response->getValue();
481 | }
482 | }
483 |
--------------------------------------------------------------------------------
/src/Traits/BaseConstants.php:
--------------------------------------------------------------------------------
1 | symfonyStyle = $symfonyStyle;
81 | $jsonFile = ($jsonFile) ? $jsonFile : $this->defaultJsonFile;
82 | $this->jsonObject = json_decode(file_get_contents($jsonFile), true);
83 | }
84 |
85 | /**
86 | * Generate class and constants
87 | *
88 | */
89 | public function generate()
90 | {
91 | $this->generateFullFile()
92 | ->createFunctions()
93 | ->createConstants()
94 | ->createConstantsFile()
95 | ->createClassFile()
96 | ->generateDocMd();
97 |
98 | $this->symfonyStyle->success("You will find output files in {$this->classFileLocation}");
99 | }
100 |
101 | public function itemList($arr)
102 | {
103 | $list = '';
104 | foreach ($arr as $value) {
105 | $listItem = (is_array($value) ? $this->itemList($value) : $value);
106 | $list .= "- $listItem";
107 | }
108 | $list .= '';
109 |
110 | return $list;
111 | }
112 |
113 | public function generateDocMd()
114 | {
115 | $columns = ['Method Name', 'HTTP', 'Url/Desc', 'Payload'];
116 | $rows = [];
117 | foreach ($this->functionsArray as $function) {
118 | $params = '';
119 | if ($function['payloadParams']) {
120 | $params = json_encode($function['payloadParams'], JSON_ERROR_UNSUPPORTED_TYPE);
121 | }
122 |
123 |
124 | $rows[] = [
125 | $function['name'],
126 | $function['http_method'],
127 | $function['url'] . "
" . $function['desc'],
128 | $params,
129 | ];
130 | }
131 | $t = new TextTable($columns, $rows);
132 | $t->maxlen = 400;
133 | //$t->setAlgin(['L', 'C', 'R']);
134 |
135 | $mdTable = $t->render();
136 |
137 | $readMeFile = __DIR__ . '/../../APPIUM_CORE_FUNCTIONS.md';
138 | $txt = file_get_contents($readMeFile);
139 | $txtNew = $this->replaceInStrWithDel($txt, '[comment]: # (core-function-comment)', $mdTable);
140 | file_put_contents($readMeFile, $txtNew);
141 | }
142 |
143 | public function replaceInStrWithDel($str, $del, $replace)
144 | {
145 | $txtArr = explode($del, $str);
146 |
147 | $newStr = join(
148 | "\n",
149 | [
150 | trim($txtArr[0]),
151 | "$del\n\n" . $replace . "\n\n$del",
152 | trim($txtArr['2']),
153 | ]
154 | );
155 |
156 | return $newStr;
157 | }
158 |
159 | public function httpMethod($str)
160 | {
161 | $isPost = stristr($str, 'POST /');
162 | if ($isPost) {
163 | return 'POST';
164 | }
165 | $isGET = stristr($str, 'GET /');
166 | if ($isGET) {
167 | return 'GET';
168 | }
169 |
170 | $isDELETE = stristr($str, 'DELETE /');
171 | if ($isDELETE) {
172 | return 'DELETE';
173 | }
174 |
175 | return 'NA';
176 | }
177 |
178 | public function getCommandNameOfUrl($url, $verb = '')
179 | {
180 | $urlExt = str_ireplace(['get', 'post', 'delete'], '', $url);
181 | $urlExt = str_ireplace('/wd/hub/session', '', $urlExt);
182 | $urlExt = preg_replace('#(:\w+)#', '', $urlExt);
183 | $urlExt = preg_replace('#\/\/#', '/', $urlExt);
184 | $urlExt = trim($urlExt, '/');
185 | $urlExt = trim($urlExt);
186 |
187 | $urlExtArr = explode('/', $urlExt);
188 | $urlExtArr = array_unique($urlExtArr);
189 | $urlExtArrLast = array_slice($urlExtArr, -2, 2);
190 |
191 |
192 | $urlStr = join('_', $urlExtArrLast);
193 | $urlStr = strtolower($verb) . '_' . $urlStr;
194 |
195 |
196 | return $urlStr;
197 | }
198 |
199 | public function toCamelCase($string, $del, $capitalizeFirstCharacter = false)
200 | {
201 |
202 | $str = str_replace($del, '', ucwords($string, $del));
203 |
204 | if (!$capitalizeFirstCharacter) {
205 | $str = lcfirst($str);
206 | }
207 |
208 | return $str;
209 | }
210 |
211 |
212 | protected function generateFullFile()
213 | {
214 | $arrCommands = [];
215 |
216 | $jsonWireObject = json_decode(file_get_contents($this->defaultJsonWireFile), true);
217 | $jsonRouteObject = json_decode(file_get_contents($this->defaultJsonRouteFile), true);
218 | $jsonRouteObjectOverRide = json_decode(file_get_contents($this->defaultJsonRouteOverrideFile), true);
219 | $extraRouteObject = json_decode(file_get_contents($this->defaultJsonExtraFile), true);
220 |
221 | $jsonRouteObjectSm = [];
222 | $jsonWireObjectSm = [];
223 |
224 | foreach ($jsonRouteObject as $key => $value) {
225 | $jsonRouteObjectSm[strtolower($key)] = $value;
226 | }
227 |
228 | foreach ($extraRouteObject as $key => $value) {
229 | $jsonRouteObjectSm[strtolower($key)] = $value;
230 | }
231 |
232 | // convert route file to method route so we can match it with jsonwire full
233 | $jsonRouteObjectSmVerb = [];
234 | foreach ($jsonRouteObjectSm as $key => $value) {
235 | foreach ($value as $verb => $verbValue) {
236 | $verbValue['http_method'] = $verb;
237 | $verbValue['src'] = 'route.json';
238 | $verbValue['link'] = ['https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js'];
239 | $jsonRouteObjectSmVerb[strtolower($verb) . ' ' . strtolower($key)] = $verbValue;
240 | }
241 | }
242 |
243 | // override
244 | foreach ($jsonRouteObjectOverRide as $key => $value) {
245 | foreach ($value as $verb => $verbValue) {
246 | $orgArr = ($jsonRouteObjectSmVerb[strtolower($verb) . ' ' . strtolower($key)]);
247 |
248 | $jsonRouteObjectSmVerb[strtolower($verb) . ' ' . strtolower($key)] = array_merge($orgArr, $verbValue);
249 | }
250 | }
251 |
252 | foreach ($jsonWireObject as $key => $commandDesc) {
253 | preg_match('#\w+ #', $key, $match);
254 | $httpMethod = trim($match[0]);
255 | $keyUrl = str_replace(' ', ' /wd/hub', $key);
256 | $jsonWireObjectSm[strtolower($keyUrl)] = [
257 | 'desc' => $commandDesc,
258 | 'http_method' => $httpMethod,
259 | 'src' => 'jsonwire-full',
260 | 'link' => ['https://github.com/admc/wd/blob/master/doc/jsonwire-full-mapping.md'],
261 | ];
262 | }
263 |
264 |
265 | // add not founds
266 | foreach ($jsonRouteObjectSmVerb as $key => $value) {
267 | $cmdDetail = $jsonWireObjectSm[$key] ?? false;
268 | if (!$cmdDetail) {
269 | $jsonWireObjectSm[$key] = [
270 | 'desc' => $key,
271 | 'http_method' => $value['http_method'],
272 | ];
273 | }
274 | }
275 |
276 | // foreach ($jsonWireObjectSm as $key => $commandDesc) {
277 | // $cmdDetail = $jsonRouteObjectSmVerb[$key] ?? false;
278 | //
279 | // if (!$cmdDetail) {
280 | // add extra Commands
281 | // $jsonWireObjectSm[$key] = [
282 | // 'desc' => $commandDesc,
283 | // 'http_method' => $httpMethod
284 | // ];
285 | // }
286 | // }
287 |
288 | foreach ($jsonWireObjectSm as $key => $commandDesc) {
289 | $cmd = $key;
290 | $urlNoVerb = str_ireplace(['post', 'get', 'delete',], '', $key);
291 | $url = str_ireplace(['/wd/hub', '/session/:sessionid'], '', $urlNoVerb);
292 | $url = trim($url);
293 |
294 | $cmdDetail = $jsonRouteObjectSmVerb[$key] ?? false;
295 |
296 | if ($cmdDetail) {
297 | if (!isset($cmdDetail['command'])) {
298 | $cmdDetail['command'] = $this->toCamelCase($this->getCommandNameOfUrl($cmd,
299 | $commandDesc['http_method']), '_');
300 | }
301 | preg_match_all('#:(\w+)#', $url, $matches);
302 | $urlParams = array_unique($matches[1]);
303 |
304 | // remove validate
305 | $payload = [];
306 |
307 | if (!empty($cmdDetail['payloadParams']['required'])) {
308 | $payload['required'] = $cmdDetail['payloadParams']['required'];
309 | }
310 |
311 | if (!empty($cmdDetail['payloadParams']['optional'])) {
312 | $payload['optional'] = $cmdDetail['payloadParams']['optional'];
313 | }
314 |
315 | $arrCommands[$key] = [
316 | 'url' => $url,
317 | 'wdUrl' => trim($urlNoVerb),
318 | 'name' => $cmdDetail['command'],
319 | 'desc' => $cmdDetail['desc'] ?? $commandDesc['desc'],
320 | 'http_method' => $this->httpMethod($key),
321 | 'uriParams' => $urlParams ?? [],
322 | 'payloadParams' => $payload,
323 | 'src' => $cmdDetail['src'] ?? '',
324 | 'note' => $cmdDetail['note'] ?? '',
325 | 'link' => $cmdDetail['link'] ?? [],
326 | ];
327 | }
328 | }
329 |
330 | file_put_contents($this->defaultJsonFile,
331 | json_encode($arrCommands, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
332 |
333 | $this->functionsArray = $arrCommands;
334 |
335 | return $this;
336 | }
337 |
338 | /**
339 | * Create functions
340 | *
341 | * @return $this
342 | *
343 | */
344 | protected function createFunctions()
345 | {
346 | if (empty($this->functionsArray)) {
347 | echo "Functions not found";
348 | die(1);
349 | }
350 |
351 | foreach ($this->functionsArray as $key => $function) {
352 | $this->addConstant(strtoupper($function['name']), $function['url']);
353 | }
354 |
355 | return $this;
356 | }
357 |
358 | /**
359 | * Create constants from template
360 | *
361 | * @return $this
362 | */
363 | protected function createConstants()
364 | {
365 | $this->constantsOutput = str_replace('{{constants}}', $this->constants, $this->constantsTemplate);
366 |
367 | return $this;
368 | }
369 |
370 | /**
371 | * Save class output in the file
372 | *
373 | * @return $this
374 | */
375 | protected function createClassFile()
376 | {
377 | foreach ($this->functionsArray as $key => $function) {
378 | if (!empty($function['url'])) {
379 | $this->writeFunction($function);
380 | }
381 | $this->classOutput .= "";
382 | }
383 |
384 | $this->classOutput = str_replace('{{functions}}', $this->classOutput, $this->classTemplate);
385 |
386 | file_put_contents($this->classFileLocation . '/' . $this->outputFileName . '.php', $this->classOutput);
387 |
388 | return $this;
389 | }
390 |
391 | /**
392 | * Write function
393 | *
394 | * @param $function
395 | *
396 | * @return string
397 | *
398 | */
399 | protected function writeFunction($function)
400 | {
401 | // Skip the routes without the command
402 | if (!isset($function['url'])) {
403 | return "";
404 | }
405 |
406 | $routeParamsString = '';
407 | $optionsAnnotations = "\n\t/**\n";
408 | $optionsAnnotations .= "\t* " . $function['name'] . "\n\t*\n";
409 |
410 | $allOptions = $function['payloadParams'];
411 |
412 | $routeParams = $function['uriParams'];
413 |
414 | if ($routeParams) {
415 | foreach ($routeParams as $key => $param) {
416 | $routeParamsString .= ($key) ? ", " : "";
417 | $routeParamsString .= "$" . $param;
418 | }
419 | }
420 |
421 | $optionsAnnotations .= ($function['desc']) ? "\t* {$function['desc']}\n" : "";
422 | $optionsAnnotations .= ($function['note']) ? "\t* @note {$function['note']}\n" : "";
423 |
424 | foreach ($function['link'] as $link) {
425 | $optionsAnnotations .= "\t* @link {$link}\n";
426 | }
427 |
428 | $optionsAnnotations .= ($function['src']) ? "\t* @source {$function['src']}\n" : "";
429 | $optionsAnnotations .= ($allOptions) ? "\t* @param array \$data\n" : "";
430 | $optionsAnnotations .= ($allOptions) ? "\t* @options " . json_encode($allOptions) . "\n\t*\n" : "";
431 | $optionsAnnotations .= ($allOptions) ? "\t* @return mixed\n" : "";
432 | $options_ = ($allOptions) ? "\$data" : "";
433 | $routeParamsString = ($allOptions && $routeParamsString) ? ", " . $routeParamsString : $routeParamsString;
434 | $this->classOutput .= $optionsAnnotations . "\t*\n\t**/\n";
435 | $this->classOutput .= "\tpublic function " . $function['name'] . "(" . $options_ . "" . $routeParamsString . "){\n";
436 |
437 | $this->classOutput .= "\t\t" . $this->getCommand($function['url'], $function['http_method'],
438 | $options_, $function['uriParams']) . "\n\t}";
439 | $this->classArray[$function['name']] = $function['name'];
440 |
441 | return $function['name'];
442 | }
443 |
444 | /**
445 | * Get the command for the function
446 | *
447 | * @param $url
448 | * @param $type
449 | * @param $data
450 | * @param $routeParams
451 | *
452 | * @return string
453 | */
454 | protected function getCommand($url, $type, $data, $routeParams)
455 | {
456 | $routeParamsString = "";
457 | $data = ($data) ? ", \$data" : '';
458 | $urlString = "'$url'";
459 | if ($routeParams) {
460 | $urlString = "\$url";
461 | $routeParamsString .= "\t\$url = '" . $url . "';\n\t\t";
462 | foreach ($routeParams as $param) {
463 | $routeParamsString .= "\t\$url = str_ireplace(':" . $param . "', $" . $param . ", \$url );\n\t\t";
464 | }
465 | }
466 | $command = $routeParamsString . "\treturn \$this->driverCommand(" . $this->constantsOutputFileName . "::$" . $type . ", " . $urlString . $data . ");";
467 |
468 | return $command;
469 | }
470 |
471 | /**
472 | * Save class output in the file
473 | *
474 | * @return $this
475 | */
476 | protected function createConstantsFile()
477 | {
478 | file_put_contents($this->classFileLocation . '/' . $this->constantsOutputFileName . '.php',
479 | $this->constantsOutput);
480 |
481 | return $this;
482 | }
483 |
484 | /**
485 | * Inspect url
486 | *
487 | * @param string $name
488 | * @param string $value
489 | *
490 | * @return mixed
491 | *
492 | */
493 | protected function addConstant($name, $value)
494 | {
495 | $nameSm = strtolower($name);
496 |
497 | if (!isset($this->constantsArray[$nameSm])) {
498 | $this->constants .= "\n\t/** @var string */\n\tpublic static \$" . $name . " = '" . $value . "';\n";
499 | $this->constantsArray[$nameSm] = $value;
500 | } else {
501 | echo "Duplicate key constants :" . $name . ' -- ' . $value . "\n";
502 | }
503 | }
504 | }
505 |
--------------------------------------------------------------------------------
/cmd/Parser/Json/AppiumCommandRoute.json:
--------------------------------------------------------------------------------
1 | {
2 | "/wd/hub/status": {
3 | "GET": {
4 | "command": "getStatus"
5 | }
6 | },
7 | "/wd/hub/session": {
8 | "POST": {
9 | "command": "createSession",
10 | "payloadParams": {
11 | "optional": [
12 | "desiredCapabilities",
13 | "requiredCapabilities",
14 | "capabilities"
15 | ]
16 | }
17 | }
18 | },
19 | "/wd/hub/sessions": {
20 | "GET": {
21 | "command": "getSessions"
22 | }
23 | },
24 | "/wd/hub/session/:sessionId": {
25 | "GET": {
26 | "command": "getSession"
27 | },
28 | "DELETE": {
29 | "command": "deleteSession"
30 | }
31 | },
32 | "/wd/hub/session/:sessionId/timeouts": {
33 | "GET": {
34 | "command": "getTimeouts"
35 | },
36 | "POST": {
37 | "command": "timeouts",
38 | "payloadParams": {
39 | "optional": [
40 | "type",
41 | "ms",
42 | "script",
43 | "pageLoad",
44 | "implicit"
45 | ]
46 | }
47 | }
48 | },
49 | "/wd/hub/session/:sessionId/timeouts/async_script": {
50 | "POST": {
51 | "command": "asyncScriptTimeout",
52 | "payloadParams": {
53 | "required": [
54 | "ms"
55 | ]
56 | }
57 | }
58 | },
59 | "/wd/hub/session/:sessionId/timeouts/implicit_wait": {
60 | "POST": {
61 | "command": "implicitWait",
62 | "payloadParams": {
63 | "required": [
64 | "ms"
65 | ]
66 | }
67 | }
68 | },
69 | "/wd/hub/session/:sessionId/window_handle": {
70 | "GET": {
71 | "command": "getWindowHandle"
72 | }
73 | },
74 | "/wd/hub/session/:sessionId/window/handle": {
75 | "GET": {
76 | "command": "getWindowHandle"
77 | }
78 | },
79 | "/wd/hub/session/:sessionId/window_handles": {
80 | "GET": {
81 | "command": "getWindowHandles"
82 | }
83 | },
84 | "/wd/hub/session/:sessionId/window/handles": {
85 | "GET": {
86 | "command": "getWindowHandles"
87 | }
88 | },
89 | "/wd/hub/session/:sessionId/url": {
90 | "GET": {
91 | "command": "getUrl"
92 | },
93 | "POST": {
94 | "command": "setUrl",
95 | "payloadParams": {
96 | "required": [
97 | "url"
98 | ]
99 | }
100 | }
101 | },
102 | "/wd/hub/session/:sessionId/forward": {
103 | "POST": {
104 | "command": "forward"
105 | }
106 | },
107 | "/wd/hub/session/:sessionId/back": {
108 | "POST": {
109 | "command": "back"
110 | }
111 | },
112 | "/wd/hub/session/:sessionId/refresh": {
113 | "POST": {
114 | "command": "refresh"
115 | }
116 | },
117 | "/wd/hub/session/:sessionId/execute": {
118 | "POST": {
119 | "command": "execute",
120 | "payloadParams": {
121 | "required": [
122 | "script",
123 | "args"
124 | ]
125 | }
126 | }
127 | },
128 | "/wd/hub/session/:sessionId/execute_async": {
129 | "POST": {
130 | "command": "executeAsync",
131 | "payloadParams": {
132 | "required": [
133 | "script",
134 | "args"
135 | ]
136 | }
137 | }
138 | },
139 | "/wd/hub/session/:sessionId/screenshot": {
140 | "GET": {
141 | "command": "getScreenshot"
142 | }
143 | },
144 | "/wd/hub/session/:sessionId/ime/available_engines": {
145 | "GET": {
146 | "command": "availableIMEEngines"
147 | }
148 | },
149 | "/wd/hub/session/:sessionId/ime/active_engine": {
150 | "GET": {
151 | "command": "getActiveIMEEngine"
152 | }
153 | },
154 | "/wd/hub/session/:sessionId/ime/activated": {
155 | "GET": {
156 | "command": "isIMEActivated"
157 | }
158 | },
159 | "/wd/hub/session/:sessionId/ime/deactivate": {
160 | "POST": {
161 | "command": "deactivateIMEEngine"
162 | }
163 | },
164 | "/wd/hub/session/:sessionId/ime/activate": {
165 | "POST": {
166 | "command": "activateIMEEngine",
167 | "payloadParams": {
168 | "required": [
169 | "engine"
170 | ]
171 | }
172 | }
173 | },
174 | "/wd/hub/session/:sessionId/frame": {
175 | "POST": {
176 | "command": "setFrame",
177 | "payloadParams": {
178 | "required": [
179 | "id"
180 | ]
181 | }
182 | }
183 | },
184 | "/wd/hub/session/:sessionId/frame/parent": {
185 | "POST": {}
186 | },
187 | "/wd/hub/session/:sessionId/window": {
188 | "GET": {
189 | "command": "getWindowHandle"
190 | },
191 | "POST": {
192 | "command": "setWindow",
193 | "payloadParams": {
194 | "optional": [
195 | "name",
196 | "handle"
197 | ]
198 | }
199 | },
200 | "DELETE": {
201 | "command": "closeWindow"
202 | }
203 | },
204 | "/wd/hub/session/:sessionId/window/:windowhandle/size": {
205 | "GET": {
206 | "command": "getWindowSize"
207 | },
208 | "POST": {}
209 | },
210 | "/wd/hub/session/:sessionId/window/:windowhandle/position": {
211 | "POST": {},
212 | "GET": {}
213 | },
214 | "/wd/hub/session/:sessionId/window/:windowhandle/maximize": {
215 | "POST": {
216 | "command": "maximizeWindow"
217 | }
218 | },
219 | "/wd/hub/session/:sessionId/cookie": {
220 | "GET": {
221 | "command": "getCookies"
222 | },
223 | "POST": {
224 | "command": "setCookie",
225 | "payloadParams": {
226 | "required": [
227 | "cookie"
228 | ]
229 | }
230 | },
231 | "DELETE": {
232 | "command": "deleteCookies"
233 | }
234 | },
235 | "/wd/hub/session/:sessionId/cookie/:name": {
236 | "GET": {
237 | "command": "getCookie"
238 | },
239 | "DELETE": {
240 | "command": "deleteCookie"
241 | }
242 | },
243 | "/wd/hub/session/:sessionId/source": {
244 | "GET": {
245 | "command": "getPageSource"
246 | }
247 | },
248 | "/wd/hub/session/:sessionId/title": {
249 | "GET": {
250 | "command": "title"
251 | }
252 | },
253 | "/wd/hub/session/:sessionId/element": {
254 | "POST": {
255 | "command": "findElement",
256 | "payloadParams": {
257 | "required": [
258 | "using",
259 | "value"
260 | ]
261 | }
262 | }
263 | },
264 | "/wd/hub/session/:sessionId/elements": {
265 | "POST": {
266 | "command": "findElements",
267 | "payloadParams": {
268 | "required": [
269 | "using",
270 | "value"
271 | ]
272 | }
273 | }
274 | },
275 | "/wd/hub/session/:sessionId/element/active": {
276 | "GET": {
277 | "command": "active"
278 | },
279 | "POST": {
280 | "command": "active"
281 | }
282 | },
283 | "/wd/hub/session/:sessionId/element/:elementId": {
284 | "GET": {}
285 | },
286 | "/wd/hub/session/:sessionId/element/:elementId/element": {
287 | "POST": {
288 | "command": "findElementFromElement",
289 | "payloadParams": {
290 | "required": [
291 | "using",
292 | "value"
293 | ]
294 | }
295 | }
296 | },
297 | "/wd/hub/session/:sessionId/element/:elementId/elements": {
298 | "POST": {
299 | "command": "findElementsFromElement",
300 | "payloadParams": {
301 | "required": [
302 | "using",
303 | "value"
304 | ]
305 | }
306 | }
307 | },
308 | "/wd/hub/session/:sessionId/element/:elementId/click": {
309 | "POST": {
310 | "command": "click"
311 | }
312 | },
313 | "/wd/hub/session/:sessionId/element/:elementId/submit": {
314 | "POST": {
315 | "command": "submit"
316 | }
317 | },
318 | "/wd/hub/session/:sessionId/element/:elementId/text": {
319 | "GET": {
320 | "command": "getText"
321 | }
322 | },
323 | "/wd/hub/session/:sessionId/element/:elementId/value": {
324 | "POST": {
325 | "command": "setValue",
326 | "payloadParams": {
327 | "optional": [
328 | "value",
329 | "text"
330 | ]
331 | }
332 | }
333 | },
334 | "/wd/hub/session/:sessionId/keys": {
335 | "POST": {
336 | "command": "keys",
337 | "payloadParams": {
338 | "required": [
339 | "value"
340 | ]
341 | }
342 | }
343 | },
344 | "/wd/hub/session/:sessionId/element/:elementId/name": {
345 | "GET": {
346 | "command": "getName"
347 | }
348 | },
349 | "/wd/hub/session/:sessionId/element/:elementId/clear": {
350 | "POST": {
351 | "command": "clear"
352 | }
353 | },
354 | "/wd/hub/session/:sessionId/element/:elementId/selected": {
355 | "GET": {
356 | "command": "elementSelected"
357 | }
358 | },
359 | "/wd/hub/session/:sessionId/element/:elementId/enabled": {
360 | "GET": {
361 | "command": "elementEnabled"
362 | }
363 | },
364 | "/wd/hub/session/:sessionId/element/:elementId/attribute/:name": {
365 | "GET": {
366 | "command": "getAttribute"
367 | }
368 | },
369 | "/wd/hub/session/:sessionId/element/:elementId/equals/:otherId": {
370 | "GET": {
371 | "command": "equalsElement"
372 | }
373 | },
374 | "/wd/hub/session/:sessionId/element/:elementId/displayed": {
375 | "GET": {
376 | "command": "elementDisplayed"
377 | }
378 | },
379 | "/wd/hub/session/:sessionId/element/:elementId/location": {
380 | "GET": {
381 | "command": "getLocation"
382 | }
383 | },
384 | "/wd/hub/session/:sessionId/element/:elementId/location_in_view": {
385 | "GET": {
386 | "command": "getLocationInView"
387 | }
388 | },
389 | "/wd/hub/session/:sessionId/element/:elementId/size": {
390 | "GET": {
391 | "command": "getSize"
392 | }
393 | },
394 | "/wd/hub/session/:sessionId/element/:elementId/css/:propertyName": {
395 | "GET": {
396 | "command": "getCssProperty"
397 | }
398 | },
399 | "/wd/hub/session/:sessionId/orientation": {
400 | "GET": {
401 | "command": "getOrientation"
402 | },
403 | "POST": {
404 | "command": "setOrientation",
405 | "payloadParams": {
406 | "required": [
407 | "orientation"
408 | ]
409 | }
410 | }
411 | },
412 | "/wd/hub/session/:sessionId/rotation": {
413 | "GET": {
414 | "command": "getRotation"
415 | },
416 | "POST": {
417 | "command": "setRotation",
418 | "payloadParams": {
419 | "required": [
420 | "x",
421 | "y",
422 | "z"
423 | ]
424 | }
425 | }
426 | },
427 | "/wd/hub/session/:sessionId/moveto": {
428 | "POST": {
429 | "command": "moveTo",
430 | "payloadParams": {
431 | "optional": [
432 | "element",
433 | "xoffset",
434 | "yoffset"
435 | ]
436 | }
437 | }
438 | },
439 | "/wd/hub/session/:sessionId/click": {
440 | "POST": {
441 | "command": "clickCurrent",
442 | "payloadParams": {
443 | "optional": [
444 | "button"
445 | ]
446 | }
447 | }
448 | },
449 | "/wd/hub/session/:sessionId/buttondown": {
450 | "POST": {}
451 | },
452 | "/wd/hub/session/:sessionId/buttonup": {
453 | "POST": {}
454 | },
455 | "/wd/hub/session/:sessionId/doubleclick": {
456 | "POST": {}
457 | },
458 | "/wd/hub/session/:sessionId/touch/click": {
459 | "POST": {
460 | "command": "click",
461 | "payloadParams": {
462 | "required": [
463 | "element"
464 | ]
465 | }
466 | }
467 | },
468 | "/wd/hub/session/:sessionId/touch/down": {
469 | "POST": {
470 | "command": "touchDown",
471 | "payloadParams": {
472 | "required": [
473 | "x",
474 | "y"
475 | ]
476 | }
477 | }
478 | },
479 | "/wd/hub/session/:sessionId/touch/up": {
480 | "POST": {
481 | "command": "touchUp",
482 | "payloadParams": {
483 | "required": [
484 | "x",
485 | "y"
486 | ]
487 | }
488 | }
489 | },
490 | "/wd/hub/session/:sessionId/touch/move": {
491 | "POST": {
492 | "command": "touchMove",
493 | "payloadParams": {
494 | "required": [
495 | "x",
496 | "y"
497 | ]
498 | }
499 | }
500 | },
501 | "/wd/hub/session/:sessionId/touch/scroll": {
502 | "POST": {}
503 | },
504 | "/wd/hub/session/:sessionId/touch/doubleclick": {
505 | "POST": {}
506 | },
507 | "/wd/hub/session/:sessionId/actions": {
508 | "POST": {
509 | "command": "performActions",
510 | "payloadParams": {
511 | "required": [
512 | "actions"
513 | ]
514 | }
515 | }
516 | },
517 | "/wd/hub/session/:sessionId/touch/longclick": {
518 | "POST": {
519 | "command": "touchLongClick",
520 | "payloadParams": {
521 | "required": [
522 | "elements"
523 | ]
524 | }
525 | }
526 | },
527 | "/wd/hub/session/:sessionId/touch/flick": {
528 | "POST": {
529 | "command": "flick",
530 | "payloadParams": {
531 | "optional": [
532 | "element",
533 | "xspeed",
534 | "yspeed",
535 | "xoffset",
536 | "yoffset",
537 | "speed"
538 | ]
539 | }
540 | }
541 | },
542 | "/wd/hub/session/:sessionId/location": {
543 | "GET": {
544 | "command": "getGeoLocation"
545 | },
546 | "POST": {
547 | "command": "setGeoLocation",
548 | "payloadParams": {
549 | "required": [
550 | "location"
551 | ]
552 | }
553 | }
554 | },
555 | "/wd/hub/session/:sessionId/local_storage": {
556 | "GET": {},
557 | "POST": {},
558 | "DELETE": {}
559 | },
560 | "/wd/hub/session/:sessionId/local_storage/key/:key": {
561 | "GET": {},
562 | "DELETE": {}
563 | },
564 | "/wd/hub/session/:sessionId/local_storage/size": {
565 | "GET": {}
566 | },
567 | "/wd/hub/session/:sessionId/session_storage": {
568 | "GET": {},
569 | "POST": {},
570 | "DELETE": {}
571 | },
572 | "/wd/hub/session/:sessionId/session_storage/key/:key": {
573 | "GET": {},
574 | "DELETE": {}
575 | },
576 | "/wd/hub/session/:sessionId/session_storage/size": {
577 | "GET": {}
578 | },
579 | "/wd/hub/session/:sessionId/log": {
580 | "POST": {
581 | "command": "getLog",
582 | "payloadParams": {
583 | "required": [
584 | "type"
585 | ]
586 | }
587 | }
588 | },
589 | "/wd/hub/session/:sessionId/log/types": {
590 | "GET": {
591 | "command": "getLogTypes"
592 | }
593 | },
594 | "/wd/hub/session/:sessionId/application_cache/status": {
595 | "GET": {}
596 | },
597 | "/wd/hub/session/:sessionId/context": {
598 | "GET": {
599 | "command": "getCurrentContext"
600 | },
601 | "POST": {
602 | "command": "setContext",
603 | "payloadParams": {
604 | "required": [
605 | "name"
606 | ]
607 | }
608 | }
609 | },
610 | "/wd/hub/session/:sessionId/contexts": {
611 | "GET": {
612 | "command": "getContexts"
613 | }
614 | },
615 | "/wd/hub/session/:sessionId/element/:elementId/pageIndex": {
616 | "GET": {
617 | "command": "getPageIndex"
618 | }
619 | },
620 | "/wd/hub/session/:sessionId/network_connection": {
621 | "GET": {
622 | "command": "getNetworkConnection"
623 | },
624 | "POST": {
625 | "command": "setNetworkConnection",
626 | "payloadParams": {
627 | "unwrap": "parameters",
628 | "required": [
629 | "type"
630 | ]
631 | }
632 | }
633 | },
634 | "/wd/hub/session/:sessionId/touch/perform": {
635 | "POST": {
636 | "command": "performTouch",
637 | "payloadParams": {
638 | "wrap": "actions",
639 | "required": [
640 | "actions"
641 | ]
642 | }
643 | }
644 | },
645 | "/wd/hub/session/:sessionId/touch/multi/perform": {
646 | "POST": {
647 | "command": "performMultiAction",
648 | "payloadParams": {
649 | "required": [
650 | "actions"
651 | ],
652 | "optional": [
653 | "elementId"
654 | ]
655 | }
656 | }
657 | },
658 | "/wd/hub/session/:sessionId/receive_async_response": {
659 | "POST": {
660 | "command": "receiveAsyncResponse",
661 | "payloadParams": {
662 | "required": [
663 | "status",
664 | "value"
665 | ]
666 | }
667 | }
668 | },
669 | "/wd/hub/session/:sessionId/appium/device/shake": {
670 | "POST": {
671 | "command": "mobileShake"
672 | }
673 | },
674 | "/wd/hub/session/:sessionId/appium/device/system_time": {
675 | "GET": {
676 | "command": "getDeviceTime",
677 | "payloadParams": {
678 | "optional": [
679 | "format"
680 | ]
681 | }
682 | }
683 | },
684 | "/wd/hub/session/:sessionId/appium/device/lock": {
685 | "POST": {
686 | "command": "lock",
687 | "payloadParams": {
688 | "optional": [
689 | "seconds"
690 | ]
691 | }
692 | }
693 | },
694 | "/wd/hub/session/:sessionId/appium/device/unlock": {
695 | "POST": {
696 | "command": "unlock"
697 | }
698 | },
699 | "/wd/hub/session/:sessionId/appium/device/is_locked": {
700 | "POST": {
701 | "command": "isLocked"
702 | }
703 | },
704 | "/wd/hub/session/:sessionId/appium/start_recording_screen": {
705 | "POST": {
706 | "command": "startRecordingScreen",
707 | "payloadParams": {
708 | "optional": [
709 | "options"
710 | ]
711 | }
712 | }
713 | },
714 | "/wd/hub/session/:sessionId/appium/stop_recording_screen": {
715 | "POST": {
716 | "command": "stopRecordingScreen",
717 | "payloadParams": {
718 | "optional": [
719 | "options"
720 | ]
721 | }
722 | }
723 | },
724 | "/wd/hub/session/:sessionId/appium/performanceData/types": {
725 | "POST": {
726 | "command": "getPerformanceDataTypes"
727 | }
728 | },
729 | "/wd/hub/session/:sessionId/appium/getPerformanceData": {
730 | "POST": {
731 | "command": "getPerformanceData",
732 | "payloadParams": {
733 | "required": [
734 | "packageName",
735 | "dataType"
736 | ],
737 | "optional": [
738 | "dataReadTimeout"
739 | ]
740 | }
741 | }
742 | },
743 | "/wd/hub/session/:sessionId/appium/device/press_keycode": {
744 | "POST": {
745 | "command": "pressKeyCode",
746 | "payloadParams": {
747 | "required": [
748 | "keycode"
749 | ],
750 | "optional": [
751 | "metastate",
752 | "flags"
753 | ]
754 | }
755 | }
756 | },
757 | "/wd/hub/session/:sessionId/appium/device/long_press_keycode": {
758 | "POST": {
759 | "command": "longPressKeyCode",
760 | "payloadParams": {
761 | "required": [
762 | "keycode"
763 | ],
764 | "optional": [
765 | "metastate",
766 | "flags"
767 | ]
768 | }
769 | }
770 | },
771 | "/wd/hub/session/:sessionId/appium/device/finger_print": {
772 | "POST": {
773 | "command": "fingerprint",
774 | "payloadParams": {
775 | "required": [
776 | "fingerprintId"
777 | ]
778 | }
779 | }
780 | },
781 | "/wd/hub/session/:sessionId/appium/device/send_sms": {
782 | "POST": {
783 | "command": "sendSMS",
784 | "payloadParams": {
785 | "required": [
786 | "phoneNumber",
787 | "message"
788 | ]
789 | }
790 | }
791 | },
792 | "/wd/hub/session/:sessionId/appium/device/gsm_call": {
793 | "POST": {
794 | "command": "gsmCall",
795 | "payloadParams": {
796 | "required": [
797 | "phoneNumber",
798 | "action"
799 | ]
800 | }
801 | }
802 | },
803 | "/wd/hub/session/:sessionId/appium/device/gsm_signal": {
804 | "POST": {
805 | "command": "gsmSignal",
806 | "payloadParams": {
807 | "required": [
808 | "signalStrengh"
809 | ]
810 | }
811 | }
812 | },
813 | "/wd/hub/session/:sessionId/appium/device/gsm_voice": {
814 | "POST": {
815 | "command": "gsmVoice",
816 | "payloadParams": {
817 | "required": [
818 | "state"
819 | ]
820 | }
821 | }
822 | },
823 | "/wd/hub/session/:sessionId/appium/device/power_capacity": {
824 | "POST": {
825 | "command": "powerCapacity",
826 | "payloadParams": {
827 | "required": [
828 | "percent"
829 | ]
830 | }
831 | }
832 | },
833 | "/wd/hub/session/:sessionId/appium/device/power_ac": {
834 | "POST": {
835 | "command": "powerAC",
836 | "payloadParams": {
837 | "required": [
838 | "state"
839 | ]
840 | }
841 | }
842 | },
843 | "/wd/hub/session/:sessionId/appium/device/network_speed": {
844 | "POST": {
845 | "command": "networkSpeed",
846 | "payloadParams": {
847 | "required": [
848 | "netspeed"
849 | ]
850 | }
851 | }
852 | },
853 | "/wd/hub/session/:sessionId/appium/device/keyevent": {
854 | "POST": {
855 | "command": "keyevent",
856 | "payloadParams": {
857 | "required": [
858 | "keycode"
859 | ],
860 | "optional": [
861 | "metastate"
862 | ]
863 | }
864 | }
865 | },
866 | "/wd/hub/session/:sessionId/appium/device/rotate": {
867 | "POST": {
868 | "command": "mobileRotation",
869 | "payloadParams": {
870 | "required": [
871 | "x",
872 | "y",
873 | "radius",
874 | "rotation",
875 | "touchCount",
876 | "duration"
877 | ],
878 | "optional": [
879 | "element"
880 | ]
881 | }
882 | }
883 | },
884 | "/wd/hub/session/:sessionId/appium/device/current_activity": {
885 | "GET": {
886 | "command": "getCurrentActivity"
887 | }
888 | },
889 | "/wd/hub/session/:sessionId/appium/device/current_package": {
890 | "GET": {
891 | "command": "getCurrentPackage"
892 | }
893 | },
894 | "/wd/hub/session/:sessionId/appium/device/install_app": {
895 | "POST": {
896 | "command": "installApp",
897 | "payloadParams": {
898 | "required": [
899 | "appPath"
900 | ],
901 | "optional": [
902 | "options"
903 | ]
904 | }
905 | }
906 | },
907 | "/wd/hub/session/:sessionId/appium/device/activate_app": {
908 | "POST": {
909 | "command": "activateApp",
910 | "payloadParams": {
911 | "required": [
912 | [
913 | "appId"
914 | ],
915 | [
916 | "bundleId"
917 | ]
918 | ],
919 | "optional": [
920 | "options"
921 | ]
922 | }
923 | }
924 | },
925 | "/wd/hub/session/:sessionId/appium/device/remove_app": {
926 | "POST": {
927 | "command": "removeApp",
928 | "payloadParams": {
929 | "required": [
930 | [
931 | "appId"
932 | ],
933 | [
934 | "bundleId"
935 | ]
936 | ],
937 | "optional": [
938 | "options"
939 | ]
940 | }
941 | }
942 | },
943 | "/wd/hub/session/:sessionId/appium/device/terminate_app": {
944 | "POST": {
945 | "command": "terminateApp",
946 | "payloadParams": {
947 | "required": [
948 | [
949 | "appId"
950 | ],
951 | [
952 | "bundleId"
953 | ]
954 | ],
955 | "optional": [
956 | "options"
957 | ]
958 | }
959 | }
960 | },
961 | "/wd/hub/session/:sessionId/appium/device/app_installed": {
962 | "POST": {
963 | "command": "isAppInstalled",
964 | "payloadParams": {
965 | "required": [
966 | [
967 | "appId"
968 | ],
969 | [
970 | "bundleId"
971 | ]
972 | ]
973 | }
974 | }
975 | },
976 | "/wd/hub/session/:sessionId/appium/device/app_state": {
977 | "GET": {
978 | "command": "queryAppState",
979 | "payloadParams": {
980 | "required": [
981 | [
982 | "appId"
983 | ],
984 | [
985 | "bundleId"
986 | ]
987 | ]
988 | }
989 | },
990 | "POST": {
991 | "command": "queryAppState",
992 | "payloadParams": {
993 | "required": [
994 | [
995 | "appId"
996 | ],
997 | [
998 | "bundleId"
999 | ]
1000 | ]
1001 | }
1002 | }
1003 | },
1004 | "/wd/hub/session/:sessionId/appium/device/hide_keyboard": {
1005 | "POST": {
1006 | "command": "hideKeyboard",
1007 | "payloadParams": {
1008 | "optional": [
1009 | "strategy",
1010 | "key",
1011 | "keyCode",
1012 | "keyName"
1013 | ]
1014 | }
1015 | }
1016 | },
1017 | "/wd/hub/session/:sessionId/appium/device/is_keyboard_shown": {
1018 | "GET": {
1019 | "command": "isKeyboardShown"
1020 | }
1021 | },
1022 | "/wd/hub/session/:sessionId/appium/device/push_file": {
1023 | "POST": {
1024 | "command": "pushFile",
1025 | "payloadParams": {
1026 | "required": [
1027 | "path",
1028 | "data"
1029 | ]
1030 | }
1031 | }
1032 | },
1033 | "/wd/hub/session/:sessionId/appium/device/pull_file": {
1034 | "POST": {
1035 | "command": "pullFile",
1036 | "payloadParams": {
1037 | "required": [
1038 | "path"
1039 | ]
1040 | }
1041 | }
1042 | },
1043 | "/wd/hub/session/:sessionId/appium/device/pull_folder": {
1044 | "POST": {
1045 | "command": "pullFolder",
1046 | "payloadParams": {
1047 | "required": [
1048 | "path"
1049 | ]
1050 | }
1051 | }
1052 | },
1053 | "/wd/hub/session/:sessionId/appium/device/toggle_airplane_mode": {
1054 | "POST": {
1055 | "command": "toggleFlightMode"
1056 | }
1057 | },
1058 | "/wd/hub/session/:sessionId/appium/device/toggle_data": {
1059 | "POST": {
1060 | "command": "toggleData"
1061 | }
1062 | },
1063 | "/wd/hub/session/:sessionId/appium/device/toggle_wifi": {
1064 | "POST": {
1065 | "command": "toggleWiFi"
1066 | }
1067 | },
1068 | "/wd/hub/session/:sessionId/appium/device/toggle_location_services": {
1069 | "POST": {
1070 | "command": "toggleLocationServices"
1071 | }
1072 | },
1073 | "/wd/hub/session/:sessionId/appium/device/open_notifications": {
1074 | "POST": {
1075 | "command": "openNotifications"
1076 | }
1077 | },
1078 | "/wd/hub/session/:sessionId/appium/device/start_activity": {
1079 | "POST": {
1080 | "command": "startActivity",
1081 | "payloadParams": {
1082 | "required": [
1083 | "appPackage",
1084 | "appActivity"
1085 | ],
1086 | "optional": [
1087 | "appWaitPackage",
1088 | "appWaitActivity",
1089 | "intentAction",
1090 | "intentCategory",
1091 | "intentFlags",
1092 | "optionalIntentArguments",
1093 | "dontStopAppOnReset"
1094 | ]
1095 | }
1096 | }
1097 | },
1098 | "/wd/hub/session/:sessionId/appium/device/system_bars": {
1099 | "GET": {
1100 | "command": "getSystemBars"
1101 | }
1102 | },
1103 | "/wd/hub/session/:sessionId/appium/device/display_density": {
1104 | "GET": {
1105 | "command": "getDisplayDensity"
1106 | }
1107 | },
1108 | "/wd/hub/session/:sessionId/appium/simulator/touch_id": {
1109 | "POST": {
1110 | "command": "touchId",
1111 | "payloadParams": {
1112 | "required": [
1113 | "match"
1114 | ]
1115 | }
1116 | }
1117 | },
1118 | "/wd/hub/session/:sessionId/appium/simulator/toggle_touch_id_enrollment": {
1119 | "POST": {
1120 | "command": "toggleEnrollTouchId",
1121 | "payloadParams": {
1122 | "optional": [
1123 | "enabled"
1124 | ]
1125 | }
1126 | }
1127 | },
1128 | "/wd/hub/session/:sessionId/appium/app/launch": {
1129 | "POST": {
1130 | "command": "launchApp"
1131 | }
1132 | },
1133 | "/wd/hub/session/:sessionId/appium/app/close": {
1134 | "POST": {
1135 | "command": "closeApp"
1136 | }
1137 | },
1138 | "/wd/hub/session/:sessionId/appium/app/reset": {
1139 | "POST": {
1140 | "command": "reset"
1141 | }
1142 | },
1143 | "/wd/hub/session/:sessionId/appium/app/background": {
1144 | "POST": {
1145 | "command": "background",
1146 | "payloadParams": {
1147 | "required": [
1148 | "seconds"
1149 | ]
1150 | }
1151 | }
1152 | },
1153 | "/wd/hub/session/:sessionId/appium/app/end_test_coverage": {
1154 | "POST": {
1155 | "command": "endCoverage",
1156 | "payloadParams": {
1157 | "required": [
1158 | "intent",
1159 | "path"
1160 | ]
1161 | }
1162 | }
1163 | },
1164 | "/wd/hub/session/:sessionId/appium/app/strings": {
1165 | "POST": {
1166 | "command": "getStrings",
1167 | "payloadParams": {
1168 | "optional": [
1169 | "language",
1170 | "stringFile"
1171 | ]
1172 | }
1173 | }
1174 | },
1175 | "/wd/hub/session/:sessionId/appium/element/:elementId/value": {
1176 | "POST": {
1177 | "command": "setValueImmediate",
1178 | "payloadParams": {
1179 | "required": [
1180 | "value"
1181 | ]
1182 | }
1183 | }
1184 | },
1185 | "/wd/hub/session/:sessionId/appium/element/:elementId/replace_value": {
1186 | "POST": {
1187 | "command": "replaceValue",
1188 | "payloadParams": {
1189 | "required": [
1190 | "value"
1191 | ]
1192 | }
1193 | }
1194 | },
1195 | "/wd/hub/session/:sessionId/appium/settings": {
1196 | "POST": {
1197 | "command": "updateSettings",
1198 | "payloadParams": {
1199 | "required": [
1200 | "settings"
1201 | ]
1202 | }
1203 | },
1204 | "GET": {
1205 | "command": "getSettings"
1206 | }
1207 | },
1208 | "/wd/hub/session/:sessionId/appium/receive_async_response": {
1209 | "POST": {
1210 | "command": "receiveAsyncResponse",
1211 | "payloadParams": {
1212 | "required": [
1213 | "response"
1214 | ]
1215 | }
1216 | }
1217 | },
1218 | "/wd/hub/session/:sessionId/alert_text": {
1219 | "GET": {
1220 | "command": "getAlertText"
1221 | },
1222 | "POST": {
1223 | "command": "setAlertText",
1224 | "payloadParams": {
1225 | "required": [
1226 | "text"
1227 | ]
1228 | }
1229 | }
1230 | },
1231 | "/wd/hub/session/:sessionId/accept_alert": {
1232 | "POST": {
1233 | "command": "postAcceptAlert"
1234 | }
1235 | },
1236 | "/wd/hub/session/:sessionId/dismiss_alert": {
1237 | "POST": {
1238 | "command": "postDismissAlert"
1239 | }
1240 | },
1241 | "/wd/hub/session/:sessionId/alert/text": {
1242 | "GET": {
1243 | "command": "getAlertText"
1244 | },
1245 | "POST": {
1246 | "command": "setAlertText",
1247 | "payloadParams": {
1248 | "optional": [
1249 | "value",
1250 | "text"
1251 | ]
1252 | }
1253 | }
1254 | },
1255 | "/wd/hub/session/:sessionId/alert/accept": {
1256 | "POST": {
1257 | "command": "postAcceptAlert"
1258 | }
1259 | },
1260 | "/wd/hub/session/:sessionId/alert/dismiss": {
1261 | "POST": {
1262 | "command": "postDismissAlert"
1263 | }
1264 | },
1265 | "/wd/hub/session/:sessionId/element/:elementId/rect": {
1266 | "GET": {
1267 | "command": "getElementRect"
1268 | }
1269 | },
1270 | "/wd/hub/session/:sessionId/execute/sync": {
1271 | "POST": {
1272 | "command": "execute",
1273 | "payloadParams": {
1274 | "required": [
1275 | "script",
1276 | "args"
1277 | ]
1278 | }
1279 | }
1280 | },
1281 | "/wd/hub/session/:sessionId/execute/async": {
1282 | "POST": {
1283 | "command": "executeAsync",
1284 | "payloadParams": {
1285 | "required": [
1286 | "script",
1287 | "args"
1288 | ]
1289 | }
1290 | }
1291 | },
1292 | "/wd/hub/session/:sessionId/screenshot/:elementId": {
1293 | "GET": {
1294 | "command": "getElementScreenshot"
1295 | }
1296 | },
1297 | "/wd/hub/session/:sessionId/element/:elementId/screenshot": {
1298 | "GET": {
1299 | "command": "getElementScreenshot"
1300 | }
1301 | },
1302 | "/wd/hub/session/:sessionId/window/rect": {
1303 | "GET": {
1304 | "command": "getWindowRect"
1305 | },
1306 | "POST": {
1307 | "command": "setWindowRect"
1308 | }
1309 | },
1310 | "/wd/hub/session/:sessionId/window/maximize": {
1311 | "POST": {
1312 | "command": "maximizeWindow"
1313 | }
1314 | },
1315 | "/wd/hub/session/:sessionId/window/minimize": {
1316 | "POST": {
1317 | "command": "minimizeWindow"
1318 | }
1319 | },
1320 | "/wd/hub/session/:sessionId/window/fullscreen": {
1321 | "POST": {
1322 | "command": "fullScreenWindow"
1323 | }
1324 | },
1325 | "/wd/hub/session/:sessionId/element/:elementId/property/:name": {
1326 | "GET": {
1327 | "command": "getProperty"
1328 | }
1329 | },
1330 | "/wd/hub/session/:sessionId/appium/device/set_clipboard": {
1331 | "POST": {
1332 | "command": "setClipboard",
1333 | "payloadParams": {
1334 | "required": [
1335 | "content"
1336 | ],
1337 | "optional": [
1338 | "contentType",
1339 | "label"
1340 | ]
1341 | }
1342 | }
1343 | },
1344 | "/wd/hub/session/:sessionId/appium/device/get_clipboard": {
1345 | "POST": {
1346 | "command": "getClipboard",
1347 | "payloadParams": {
1348 | "optional": [
1349 | "contentType"
1350 | ]
1351 | }
1352 | }
1353 | },
1354 | "/wd/hub/session/:sessionId/appium/compare_images": {
1355 | "POST": {
1356 | "command": "compareImages",
1357 | "payloadParams": {
1358 | "required": [
1359 | "mode",
1360 | "firstImage",
1361 | "secondImage"
1362 | ],
1363 | "optional": [
1364 | "options"
1365 | ]
1366 | }
1367 | }
1368 | }
1369 | }
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | ajv@^6.5.5:
6 | version "6.6.2"
7 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d"
8 | integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==
9 | dependencies:
10 | fast-deep-equal "^2.0.1"
11 | fast-json-stable-stringify "^2.0.0"
12 | json-schema-traverse "^0.4.1"
13 | uri-js "^4.2.2"
14 |
15 | all-contributors-cli@^4.10.1:
16 | version "4.11.2"
17 | resolved "https://registry.yarnpkg.com/all-contributors-cli/-/all-contributors-cli-4.11.2.tgz#b8bf1e1d08181be76ca4ebeb7869d3fdfbcf5557"
18 | integrity sha512-E1hfoxpCWes+YUvYP9IuaQMg6gs//5iRearVeDfgrxUNr6MFP0BGJwhZb33usiNCO7Sl3lasbpAfWNmfvXb1Bg==
19 | dependencies:
20 | async "^2.0.0-rc.1"
21 | chalk "^2.3.0"
22 | inquirer "^4.0.0"
23 | lodash "^4.11.2"
24 | pify "^3.0.0"
25 | request "^2.72.0"
26 | yargs "^10.0.3"
27 |
28 | ansi-escapes@^3.0.0:
29 | version "3.1.0"
30 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30"
31 | integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==
32 |
33 | ansi-regex@^2.0.0:
34 | version "2.1.1"
35 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
36 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
37 |
38 | ansi-regex@^3.0.0:
39 | version "3.0.0"
40 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
41 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
42 |
43 | ansi-styles@^3.2.1:
44 | version "3.2.1"
45 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
46 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
47 | dependencies:
48 | color-convert "^1.9.0"
49 |
50 | asn1@~0.2.3:
51 | version "0.2.4"
52 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
53 | integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
54 | dependencies:
55 | safer-buffer "~2.1.0"
56 |
57 | assert-plus@1.0.0, assert-plus@^1.0.0:
58 | version "1.0.0"
59 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
60 | integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
61 |
62 | async@^2.0.0-rc.1:
63 | version "2.6.1"
64 | resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
65 | integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==
66 | dependencies:
67 | lodash "^4.17.10"
68 |
69 | asynckit@^0.4.0:
70 | version "0.4.0"
71 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
72 | integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
73 |
74 | aws-sign2@~0.7.0:
75 | version "0.7.0"
76 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
77 | integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
78 |
79 | aws4@^1.8.0:
80 | version "1.8.0"
81 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
82 | integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
83 |
84 | bcrypt-pbkdf@^1.0.0:
85 | version "1.0.2"
86 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
87 | integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
88 | dependencies:
89 | tweetnacl "^0.14.3"
90 |
91 | camelcase@^4.1.0:
92 | version "4.1.0"
93 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
94 | integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
95 |
96 | caseless@~0.12.0:
97 | version "0.12.0"
98 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
99 | integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
100 |
101 | chalk@^2.0.0, chalk@^2.3.0:
102 | version "2.4.1"
103 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
104 | integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==
105 | dependencies:
106 | ansi-styles "^3.2.1"
107 | escape-string-regexp "^1.0.5"
108 | supports-color "^5.3.0"
109 |
110 | chardet@^0.4.0:
111 | version "0.4.2"
112 | resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
113 | integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=
114 |
115 | cli-cursor@^2.1.0:
116 | version "2.1.0"
117 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
118 | integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
119 | dependencies:
120 | restore-cursor "^2.0.0"
121 |
122 | cli-width@^2.0.0:
123 | version "2.2.0"
124 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
125 | integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
126 |
127 | cliui@^4.0.0:
128 | version "4.1.0"
129 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
130 | integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==
131 | dependencies:
132 | string-width "^2.1.1"
133 | strip-ansi "^4.0.0"
134 | wrap-ansi "^2.0.0"
135 |
136 | code-point-at@^1.0.0:
137 | version "1.1.0"
138 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
139 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
140 |
141 | color-convert@^1.9.0:
142 | version "1.9.3"
143 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
144 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
145 | dependencies:
146 | color-name "1.1.3"
147 |
148 | color-name@1.1.3:
149 | version "1.1.3"
150 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
151 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
152 |
153 | combined-stream@^1.0.6, combined-stream@~1.0.6:
154 | version "1.0.7"
155 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
156 | integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==
157 | dependencies:
158 | delayed-stream "~1.0.0"
159 |
160 | core-util-is@1.0.2:
161 | version "1.0.2"
162 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
163 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
164 |
165 | cross-spawn@^5.0.1:
166 | version "5.1.0"
167 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
168 | integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
169 | dependencies:
170 | lru-cache "^4.0.1"
171 | shebang-command "^1.2.0"
172 | which "^1.2.9"
173 |
174 | dashdash@^1.12.0:
175 | version "1.14.1"
176 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
177 | integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
178 | dependencies:
179 | assert-plus "^1.0.0"
180 |
181 | decamelize@^1.1.1:
182 | version "1.2.0"
183 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
184 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
185 |
186 | delayed-stream@~1.0.0:
187 | version "1.0.0"
188 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
189 | integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
190 |
191 | ecc-jsbn@~0.1.1:
192 | version "0.1.2"
193 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
194 | integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
195 | dependencies:
196 | jsbn "~0.1.0"
197 | safer-buffer "^2.1.0"
198 |
199 | escape-string-regexp@^1.0.5:
200 | version "1.0.5"
201 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
202 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
203 |
204 | execa@^0.7.0:
205 | version "0.7.0"
206 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
207 | integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
208 | dependencies:
209 | cross-spawn "^5.0.1"
210 | get-stream "^3.0.0"
211 | is-stream "^1.1.0"
212 | npm-run-path "^2.0.0"
213 | p-finally "^1.0.0"
214 | signal-exit "^3.0.0"
215 | strip-eof "^1.0.0"
216 |
217 | extend@~3.0.2:
218 | version "3.0.2"
219 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
220 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
221 |
222 | external-editor@^2.1.0:
223 | version "2.2.0"
224 | resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5"
225 | integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==
226 | dependencies:
227 | chardet "^0.4.0"
228 | iconv-lite "^0.4.17"
229 | tmp "^0.0.33"
230 |
231 | extsprintf@1.3.0:
232 | version "1.3.0"
233 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
234 | integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
235 |
236 | extsprintf@^1.2.0:
237 | version "1.4.0"
238 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
239 | integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
240 |
241 | fast-deep-equal@^2.0.1:
242 | version "2.0.1"
243 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
244 | integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
245 |
246 | fast-json-stable-stringify@^2.0.0:
247 | version "2.0.0"
248 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
249 | integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
250 |
251 | figures@^2.0.0:
252 | version "2.0.0"
253 | resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
254 | integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
255 | dependencies:
256 | escape-string-regexp "^1.0.5"
257 |
258 | find-up@^2.1.0:
259 | version "2.1.0"
260 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
261 | integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
262 | dependencies:
263 | locate-path "^2.0.0"
264 |
265 | forever-agent@~0.6.1:
266 | version "0.6.1"
267 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
268 | integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
269 |
270 | form-data@~2.3.2:
271 | version "2.3.3"
272 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
273 | integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
274 | dependencies:
275 | asynckit "^0.4.0"
276 | combined-stream "^1.0.6"
277 | mime-types "^2.1.12"
278 |
279 | get-caller-file@^1.0.1:
280 | version "1.0.3"
281 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
282 | integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
283 |
284 | get-stream@^3.0.0:
285 | version "3.0.0"
286 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
287 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
288 |
289 | getpass@^0.1.1:
290 | version "0.1.7"
291 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
292 | integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
293 | dependencies:
294 | assert-plus "^1.0.0"
295 |
296 | har-schema@^2.0.0:
297 | version "2.0.0"
298 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
299 | integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
300 |
301 | har-validator@~5.1.0:
302 | version "5.1.3"
303 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
304 | integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
305 | dependencies:
306 | ajv "^6.5.5"
307 | har-schema "^2.0.0"
308 |
309 | has-flag@^3.0.0:
310 | version "3.0.0"
311 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
312 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
313 |
314 | http-signature@~1.2.0:
315 | version "1.2.0"
316 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
317 | integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
318 | dependencies:
319 | assert-plus "^1.0.0"
320 | jsprim "^1.2.2"
321 | sshpk "^1.7.0"
322 |
323 | iconv-lite@^0.4.17:
324 | version "0.4.24"
325 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
326 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
327 | dependencies:
328 | safer-buffer ">= 2.1.2 < 3"
329 |
330 | inquirer@^4.0.0:
331 | version "4.0.2"
332 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-4.0.2.tgz#cc678b4cbc0e183a3500cc63395831ec956ab0a3"
333 | integrity sha512-+f3qDNeZpkhFJ61NBA9jXDrGGhoQuqfEum9A681c9oHoIbGgVqjogKynjB/vNVP+nVu9w3FbFQ35c0ibU0MaIQ==
334 | dependencies:
335 | ansi-escapes "^3.0.0"
336 | chalk "^2.0.0"
337 | cli-cursor "^2.1.0"
338 | cli-width "^2.0.0"
339 | external-editor "^2.1.0"
340 | figures "^2.0.0"
341 | lodash "^4.3.0"
342 | mute-stream "0.0.7"
343 | run-async "^2.2.0"
344 | rx-lite "^4.0.8"
345 | rx-lite-aggregates "^4.0.8"
346 | string-width "^2.1.0"
347 | strip-ansi "^4.0.0"
348 | through "^2.3.6"
349 |
350 | invert-kv@^1.0.0:
351 | version "1.0.0"
352 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
353 | integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
354 |
355 | is-fullwidth-code-point@^1.0.0:
356 | version "1.0.0"
357 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
358 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
359 | dependencies:
360 | number-is-nan "^1.0.0"
361 |
362 | is-fullwidth-code-point@^2.0.0:
363 | version "2.0.0"
364 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
365 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
366 |
367 | is-promise@^2.1.0:
368 | version "2.1.0"
369 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
370 | integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
371 |
372 | is-stream@^1.1.0:
373 | version "1.1.0"
374 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
375 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
376 |
377 | is-typedarray@~1.0.0:
378 | version "1.0.0"
379 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
380 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
381 |
382 | isexe@^2.0.0:
383 | version "2.0.0"
384 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
385 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
386 |
387 | isstream@~0.1.2:
388 | version "0.1.2"
389 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
390 | integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
391 |
392 | jsbn@~0.1.0:
393 | version "0.1.1"
394 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
395 | integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
396 |
397 | json-schema-traverse@^0.4.1:
398 | version "0.4.1"
399 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
400 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
401 |
402 | json-schema@0.2.3:
403 | version "0.2.3"
404 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
405 | integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
406 |
407 | json-stringify-safe@~5.0.1:
408 | version "5.0.1"
409 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
410 | integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
411 |
412 | jsprim@^1.2.2:
413 | version "1.4.1"
414 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
415 | integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
416 | dependencies:
417 | assert-plus "1.0.0"
418 | extsprintf "1.3.0"
419 | json-schema "0.2.3"
420 | verror "1.10.0"
421 |
422 | lcid@^1.0.0:
423 | version "1.0.0"
424 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
425 | integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
426 | dependencies:
427 | invert-kv "^1.0.0"
428 |
429 | locate-path@^2.0.0:
430 | version "2.0.0"
431 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
432 | integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
433 | dependencies:
434 | p-locate "^2.0.0"
435 | path-exists "^3.0.0"
436 |
437 | lodash@^4.11.2, lodash@^4.17.10, lodash@^4.3.0:
438 | version "4.17.11"
439 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
440 | integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
441 |
442 | lru-cache@^4.0.1:
443 | version "4.1.5"
444 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
445 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
446 | dependencies:
447 | pseudomap "^1.0.2"
448 | yallist "^2.1.2"
449 |
450 | mem@^1.1.0:
451 | version "1.1.0"
452 | resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76"
453 | integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=
454 | dependencies:
455 | mimic-fn "^1.0.0"
456 |
457 | mime-db@~1.37.0:
458 | version "1.37.0"
459 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8"
460 | integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==
461 |
462 | mime-types@^2.1.12, mime-types@~2.1.19:
463 | version "2.1.21"
464 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96"
465 | integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==
466 | dependencies:
467 | mime-db "~1.37.0"
468 |
469 | mimic-fn@^1.0.0:
470 | version "1.2.0"
471 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
472 | integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
473 |
474 | mute-stream@0.0.7:
475 | version "0.0.7"
476 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
477 | integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
478 |
479 | npm-run-path@^2.0.0:
480 | version "2.0.2"
481 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
482 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
483 | dependencies:
484 | path-key "^2.0.0"
485 |
486 | number-is-nan@^1.0.0:
487 | version "1.0.1"
488 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
489 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
490 |
491 | oauth-sign@~0.9.0:
492 | version "0.9.0"
493 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
494 | integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
495 |
496 | onetime@^2.0.0:
497 | version "2.0.1"
498 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
499 | integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
500 | dependencies:
501 | mimic-fn "^1.0.0"
502 |
503 | os-locale@^2.0.0:
504 | version "2.1.0"
505 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2"
506 | integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==
507 | dependencies:
508 | execa "^0.7.0"
509 | lcid "^1.0.0"
510 | mem "^1.1.0"
511 |
512 | os-tmpdir@~1.0.2:
513 | version "1.0.2"
514 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
515 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
516 |
517 | p-finally@^1.0.0:
518 | version "1.0.0"
519 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
520 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
521 |
522 | p-limit@^1.1.0:
523 | version "1.3.0"
524 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
525 | integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
526 | dependencies:
527 | p-try "^1.0.0"
528 |
529 | p-locate@^2.0.0:
530 | version "2.0.0"
531 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
532 | integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
533 | dependencies:
534 | p-limit "^1.1.0"
535 |
536 | p-try@^1.0.0:
537 | version "1.0.0"
538 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
539 | integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
540 |
541 | path-exists@^3.0.0:
542 | version "3.0.0"
543 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
544 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
545 |
546 | path-key@^2.0.0:
547 | version "2.0.1"
548 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
549 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
550 |
551 | performance-now@^2.1.0:
552 | version "2.1.0"
553 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
554 | integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
555 |
556 | pify@^3.0.0:
557 | version "3.0.0"
558 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
559 | integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
560 |
561 | pseudomap@^1.0.2:
562 | version "1.0.2"
563 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
564 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
565 |
566 | psl@^1.1.24:
567 | version "1.1.31"
568 | resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184"
569 | integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==
570 |
571 | punycode@^1.4.1:
572 | version "1.4.1"
573 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
574 | integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
575 |
576 | punycode@^2.1.0:
577 | version "2.1.1"
578 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
579 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
580 |
581 | qs@~6.5.2:
582 | version "6.5.3"
583 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
584 | integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
585 |
586 | request@^2.72.0:
587 | version "2.88.0"
588 | resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
589 | integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
590 | dependencies:
591 | aws-sign2 "~0.7.0"
592 | aws4 "^1.8.0"
593 | caseless "~0.12.0"
594 | combined-stream "~1.0.6"
595 | extend "~3.0.2"
596 | forever-agent "~0.6.1"
597 | form-data "~2.3.2"
598 | har-validator "~5.1.0"
599 | http-signature "~1.2.0"
600 | is-typedarray "~1.0.0"
601 | isstream "~0.1.2"
602 | json-stringify-safe "~5.0.1"
603 | mime-types "~2.1.19"
604 | oauth-sign "~0.9.0"
605 | performance-now "^2.1.0"
606 | qs "~6.5.2"
607 | safe-buffer "^5.1.2"
608 | tough-cookie "~2.4.3"
609 | tunnel-agent "^0.6.0"
610 | uuid "^3.3.2"
611 |
612 | require-directory@^2.1.1:
613 | version "2.1.1"
614 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
615 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
616 |
617 | require-main-filename@^1.0.1:
618 | version "1.0.1"
619 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
620 | integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
621 |
622 | restore-cursor@^2.0.0:
623 | version "2.0.0"
624 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
625 | integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
626 | dependencies:
627 | onetime "^2.0.0"
628 | signal-exit "^3.0.2"
629 |
630 | run-async@^2.2.0:
631 | version "2.3.0"
632 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
633 | integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
634 | dependencies:
635 | is-promise "^2.1.0"
636 |
637 | rx-lite-aggregates@^4.0.8:
638 | version "4.0.8"
639 | resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
640 | integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=
641 | dependencies:
642 | rx-lite "*"
643 |
644 | rx-lite@*, rx-lite@^4.0.8:
645 | version "4.0.8"
646 | resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
647 | integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=
648 |
649 | safe-buffer@^5.0.1, safe-buffer@^5.1.2:
650 | version "5.1.2"
651 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
652 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
653 |
654 | "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
655 | version "2.1.2"
656 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
657 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
658 |
659 | set-blocking@^2.0.0:
660 | version "2.0.0"
661 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
662 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
663 |
664 | shebang-command@^1.2.0:
665 | version "1.2.0"
666 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
667 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
668 | dependencies:
669 | shebang-regex "^1.0.0"
670 |
671 | shebang-regex@^1.0.0:
672 | version "1.0.0"
673 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
674 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
675 |
676 | signal-exit@^3.0.0, signal-exit@^3.0.2:
677 | version "3.0.2"
678 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
679 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
680 |
681 | sshpk@^1.7.0:
682 | version "1.16.0"
683 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.0.tgz#1d4963a2fbffe58050aa9084ca20be81741c07de"
684 | integrity sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==
685 | dependencies:
686 | asn1 "~0.2.3"
687 | assert-plus "^1.0.0"
688 | bcrypt-pbkdf "^1.0.0"
689 | dashdash "^1.12.0"
690 | ecc-jsbn "~0.1.1"
691 | getpass "^0.1.1"
692 | jsbn "~0.1.0"
693 | safer-buffer "^2.0.2"
694 | tweetnacl "~0.14.0"
695 |
696 | string-width@^1.0.1:
697 | version "1.0.2"
698 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
699 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
700 | dependencies:
701 | code-point-at "^1.0.0"
702 | is-fullwidth-code-point "^1.0.0"
703 | strip-ansi "^3.0.0"
704 |
705 | string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
706 | version "2.1.1"
707 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
708 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
709 | dependencies:
710 | is-fullwidth-code-point "^2.0.0"
711 | strip-ansi "^4.0.0"
712 |
713 | strip-ansi@^3.0.0, strip-ansi@^3.0.1:
714 | version "3.0.1"
715 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
716 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
717 | dependencies:
718 | ansi-regex "^2.0.0"
719 |
720 | strip-ansi@^4.0.0:
721 | version "4.0.0"
722 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
723 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
724 | dependencies:
725 | ansi-regex "^3.0.0"
726 |
727 | strip-eof@^1.0.0:
728 | version "1.0.0"
729 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
730 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
731 |
732 | supports-color@^5.3.0:
733 | version "5.5.0"
734 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
735 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
736 | dependencies:
737 | has-flag "^3.0.0"
738 |
739 | through@^2.3.6:
740 | version "2.3.8"
741 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
742 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
743 |
744 | tmp@^0.0.33:
745 | version "0.0.33"
746 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
747 | integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
748 | dependencies:
749 | os-tmpdir "~1.0.2"
750 |
751 | tough-cookie@~2.4.3:
752 | version "2.4.3"
753 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
754 | integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
755 | dependencies:
756 | psl "^1.1.24"
757 | punycode "^1.4.1"
758 |
759 | tunnel-agent@^0.6.0:
760 | version "0.6.0"
761 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
762 | integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
763 | dependencies:
764 | safe-buffer "^5.0.1"
765 |
766 | tweetnacl@^0.14.3, tweetnacl@~0.14.0:
767 | version "0.14.5"
768 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
769 | integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
770 |
771 | uri-js@^4.2.2:
772 | version "4.2.2"
773 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
774 | integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
775 | dependencies:
776 | punycode "^2.1.0"
777 |
778 | uuid@^3.3.2:
779 | version "3.3.2"
780 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
781 | integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
782 |
783 | verror@1.10.0:
784 | version "1.10.0"
785 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
786 | integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
787 | dependencies:
788 | assert-plus "^1.0.0"
789 | core-util-is "1.0.2"
790 | extsprintf "^1.2.0"
791 |
792 | which-module@^2.0.0:
793 | version "2.0.0"
794 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
795 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
796 |
797 | which@^1.2.9:
798 | version "1.3.1"
799 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
800 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
801 | dependencies:
802 | isexe "^2.0.0"
803 |
804 | wrap-ansi@^2.0.0:
805 | version "2.1.0"
806 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
807 | integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
808 | dependencies:
809 | string-width "^1.0.1"
810 | strip-ansi "^3.0.1"
811 |
812 | y18n@^3.2.1:
813 | version "3.2.1"
814 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
815 | integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
816 |
817 | yallist@^2.1.2:
818 | version "2.1.2"
819 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
820 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
821 |
822 | yargs-parser@^8.1.0:
823 | version "8.1.0"
824 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950"
825 | integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==
826 | dependencies:
827 | camelcase "^4.1.0"
828 |
829 | yargs@^10.0.3:
830 | version "10.1.2"
831 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5"
832 | integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==
833 | dependencies:
834 | cliui "^4.0.0"
835 | decamelize "^1.1.1"
836 | find-up "^2.1.0"
837 | get-caller-file "^1.0.1"
838 | os-locale "^2.0.0"
839 | require-directory "^2.1.1"
840 | require-main-filename "^1.0.1"
841 | set-blocking "^2.0.0"
842 | string-width "^2.0.0"
843 | which-module "^2.0.0"
844 | y18n "^3.2.1"
845 | yargs-parser "^8.1.0"
846 |
--------------------------------------------------------------------------------