rspec-tapas 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +45 -0
- data/.rspec +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +51 -20
- data/README.md +3 -3
- data/VERSION +1 -1
- data/lib/rspec_tapas/all.rb +1 -0
- data/lib/rspec_tapas/matchers/have_table_row.rb +30 -25
- data/rspec-tapas.gemspec +9 -5
- data/spec/rspec_tapas/matchers/have_table_row_spec.rb +130 -0
- data/spec/spec_helper.rb +20 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 60861eb78b60849b8a154122f8f20e5911a89dbdb20c87c69086ef49f20855bb
|
4
|
+
data.tar.gz: b0e390adc249196f84431dadd3954bf28a844b56874e3e37a405e7ad7e95ba54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a10b919e867f25e691efb313fb211b01e94fb1a1fc98f91ac3bfee21210d4e0619dfc41dca9cc3108196b92b291ae600a65783ba12945e052dbe6ca5628b211c
|
7
|
+
data.tar.gz: d0ebb79f5049fb20e10a3a5deb829624891201be8b5a7f7fcea121e546f1d1109bb9325b8e8d9771d3373e9dd3839f3e88ebeecce119bc4851c991ef914124ef
|
@@ -0,0 +1,45 @@
|
|
1
|
+
version: 2
|
2
|
+
jobs:
|
3
|
+
build:
|
4
|
+
docker:
|
5
|
+
- image: circleci/ruby:2.5.1-node-browsers
|
6
|
+
environment:
|
7
|
+
RAILS_ENV: test
|
8
|
+
BUNDLE_JOBS: "3"
|
9
|
+
BUNDLE_RETRY: "3"
|
10
|
+
BUNDLE_PATH: vendor/bundle
|
11
|
+
|
12
|
+
steps:
|
13
|
+
- checkout
|
14
|
+
|
15
|
+
- restore_cache:
|
16
|
+
keys:
|
17
|
+
- gems-{{ checksum "Gemfile.lock" }}
|
18
|
+
|
19
|
+
- run:
|
20
|
+
name: Install dependencies
|
21
|
+
command: |
|
22
|
+
bundle check || bundle install
|
23
|
+
|
24
|
+
- save_cache:
|
25
|
+
key: gems-{{ checksum "Gemfile.lock" }}
|
26
|
+
paths:
|
27
|
+
- ./vendor/bundle
|
28
|
+
|
29
|
+
- run:
|
30
|
+
name: Run tests
|
31
|
+
command: |
|
32
|
+
mkdir /tmp/test-results
|
33
|
+
TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
|
34
|
+
|
35
|
+
bundle exec rspec --format documentation \
|
36
|
+
--out /tmp/test-results/rspec.txt \
|
37
|
+
--format progress \
|
38
|
+
$TEST_FILES
|
39
|
+
|
40
|
+
- store_test_results:
|
41
|
+
path: /tmp/test-results
|
42
|
+
|
43
|
+
- store_artifacts:
|
44
|
+
path: /tmp/test-results
|
45
|
+
destination: test-results
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -6,24 +6,33 @@ GEM
|
|
6
6
|
i18n (>= 0.7, < 2)
|
7
7
|
minitest (~> 5.1)
|
8
8
|
tzinfo (~> 1.1)
|
9
|
-
addressable (2.
|
10
|
-
public_suffix (>= 2.0.2, <
|
11
|
-
builder (3.2.
|
9
|
+
addressable (2.7.0)
|
10
|
+
public_suffix (>= 2.0.2, < 5.0)
|
11
|
+
builder (3.2.4)
|
12
|
+
capybara (3.3.1)
|
13
|
+
addressable
|
14
|
+
mini_mime (>= 0.1.3)
|
15
|
+
nokogiri (~> 1.8)
|
16
|
+
rack (>= 1.6.0)
|
17
|
+
rack-test (>= 0.6.3)
|
18
|
+
xpath (~> 3.1)
|
12
19
|
concurrent-ruby (1.0.5)
|
13
20
|
descendants_tracker (0.0.4)
|
14
21
|
thread_safe (~> 0.3, >= 0.3.1)
|
22
|
+
diff-lcs (1.3)
|
15
23
|
docile (1.3.1)
|
16
|
-
faraday (0.
|
24
|
+
faraday (0.17.3)
|
17
25
|
multipart-post (>= 1.2, < 3)
|
18
|
-
git (1.
|
26
|
+
git (1.6.0)
|
27
|
+
rchardet (~> 1.8)
|
19
28
|
github_api (0.18.2)
|
20
29
|
addressable (~> 2.4)
|
21
30
|
descendants_tracker (~> 0.0.4)
|
22
31
|
faraday (~> 0.8)
|
23
32
|
hashie (~> 3.5, >= 3.5.2)
|
24
33
|
oauth2 (~> 1.0)
|
25
|
-
hashie (3.
|
26
|
-
highline (2.0.
|
34
|
+
hashie (3.6.0)
|
35
|
+
highline (2.0.3)
|
27
36
|
i18n (1.0.1)
|
28
37
|
concurrent-ruby (~> 1.0)
|
29
38
|
json (1.8.6)
|
@@ -37,25 +46,42 @@ GEM
|
|
37
46
|
rake
|
38
47
|
rdoc
|
39
48
|
semver
|
40
|
-
jwt (
|
41
|
-
|
49
|
+
jwt (2.2.1)
|
50
|
+
mini_mime (1.0.0)
|
51
|
+
mini_portile2 (2.4.0)
|
42
52
|
minitest (5.11.3)
|
43
|
-
multi_json (1.
|
53
|
+
multi_json (1.14.1)
|
44
54
|
multi_xml (0.6.0)
|
45
|
-
multipart-post (2.
|
46
|
-
nokogiri (1.
|
47
|
-
mini_portile2 (~> 2.
|
48
|
-
oauth2 (1.4.
|
49
|
-
faraday (>= 0.8, < 0
|
50
|
-
jwt (
|
55
|
+
multipart-post (2.1.1)
|
56
|
+
nokogiri (1.10.7)
|
57
|
+
mini_portile2 (~> 2.4.0)
|
58
|
+
oauth2 (1.4.3)
|
59
|
+
faraday (>= 0.8, < 2.0)
|
60
|
+
jwt (>= 1.0, < 3.0)
|
51
61
|
multi_json (~> 1.3)
|
52
62
|
multi_xml (~> 0.5)
|
53
63
|
rack (>= 1.2, < 3)
|
54
|
-
public_suffix (
|
55
|
-
rack (2.
|
56
|
-
|
64
|
+
public_suffix (4.0.3)
|
65
|
+
rack (2.1.2)
|
66
|
+
rack-test (1.0.0)
|
67
|
+
rack (>= 1.0, < 3)
|
68
|
+
rake (13.0.1)
|
69
|
+
rchardet (1.8.0)
|
57
70
|
rdoc (3.12.2)
|
58
71
|
json (~> 1.4)
|
72
|
+
rspec (3.7.0)
|
73
|
+
rspec-core (~> 3.7.0)
|
74
|
+
rspec-expectations (~> 3.7.0)
|
75
|
+
rspec-mocks (~> 3.7.0)
|
76
|
+
rspec-core (3.7.1)
|
77
|
+
rspec-support (~> 3.7.0)
|
78
|
+
rspec-expectations (3.7.0)
|
79
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
80
|
+
rspec-support (~> 3.7.0)
|
81
|
+
rspec-mocks (3.7.0)
|
82
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
83
|
+
rspec-support (~> 3.7.0)
|
84
|
+
rspec-support (3.7.1)
|
59
85
|
semver (1.0.1)
|
60
86
|
shoulda (3.5.0)
|
61
87
|
shoulda-context (~> 1.0, >= 1.0.1)
|
@@ -71,16 +97,21 @@ GEM
|
|
71
97
|
thread_safe (0.3.6)
|
72
98
|
tzinfo (1.2.5)
|
73
99
|
thread_safe (~> 0.1)
|
100
|
+
xpath (3.1.0)
|
101
|
+
nokogiri (~> 1.8)
|
74
102
|
|
75
103
|
PLATFORMS
|
76
104
|
ruby
|
77
105
|
|
78
106
|
DEPENDENCIES
|
107
|
+
activesupport
|
79
108
|
bundler (~> 1.0)
|
109
|
+
capybara
|
80
110
|
juwelier (~> 2.1.0)
|
81
111
|
rdoc (~> 3.12)
|
112
|
+
rspec
|
82
113
|
shoulda
|
83
114
|
simplecov
|
84
115
|
|
85
116
|
BUNDLED WITH
|
86
|
-
1.
|
117
|
+
1.17.2
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@ rspec-tapas is a set of small helpers and extensions we often use in [Selleo](ht
|
|
7
7
|
To install rspec-tapas just add following line to your `Gemfile`s `:test` group
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
gem '
|
10
|
+
gem 'rspec-tapas'
|
11
11
|
```
|
12
12
|
|
13
13
|
then just `bundle install` and require it in `rails_helper.rb`
|
@@ -150,7 +150,7 @@ RSpec.describe ReportMailer, type: :mailer do
|
|
150
150
|
expect(html_part(mail)).to include_html(
|
151
151
|
<<~HTML
|
152
152
|
<h1>Orders summary</h1>
|
153
|
-
<strong>Total orders created:</strong> 2 <br />
|
153
|
+
<strong>Total orders created:</strong> 2 <br />
|
154
154
|
HTML
|
155
155
|
)
|
156
156
|
expect(text_part(mail)).to include('Total orders created: 2')
|
@@ -301,4 +301,4 @@ expect(page).to have_table_row('Tony', 'Stark', 4.5)
|
|
301
301
|
expect(page).to have_table_row(have_content('ny'), 'Stark')
|
302
302
|
```
|
303
303
|
|
304
|
-
To include this matcher
|
304
|
+
To include this matcher use: `config.include RSpecTapas::Matchers`
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/lib/rspec_tapas/all.rb
CHANGED
@@ -1,38 +1,43 @@
|
|
1
1
|
require_relative '../locators/find_table_row.rb'
|
2
2
|
require 'rspec/expectations'
|
3
|
+
require 'capybara'
|
3
4
|
|
4
5
|
Capybara::Session.include FindTableRow
|
5
6
|
Capybara::Node::Simple.include FindTableRow
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
page
|
11
|
-
|
12
|
-
|
8
|
+
module RSpecTapas
|
9
|
+
module Matchers
|
10
|
+
RSpec::Matchers.define :have_table_row do |*expected|
|
11
|
+
match do |page|
|
12
|
+
with_delay do
|
13
|
+
page.find_table_row(*expected)
|
14
|
+
end
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
match_when_negated do
|
18
|
+
page.find_table_row(*expected)
|
19
|
+
false
|
20
|
+
rescue Capybara::ElementNotFound
|
21
|
+
true
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
failure_message do
|
25
|
+
@failure_message
|
26
|
+
end
|
24
27
|
|
25
|
-
|
28
|
+
private
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
def with_delay
|
31
|
+
Timeout.timeout(Capybara.default_max_wait_time) do
|
32
|
+
yield
|
33
|
+
rescue => error
|
34
|
+
@failure_message = error.message
|
35
|
+
sleep(1)
|
36
|
+
retry
|
37
|
+
end
|
38
|
+
rescue Timeout::Error
|
39
|
+
false
|
40
|
+
end
|
34
41
|
end
|
35
|
-
rescue Timeout::Error
|
36
|
-
false
|
37
42
|
end
|
38
43
|
end
|
data/rspec-tapas.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: rspec-tapas 0.2.
|
5
|
+
# stub: rspec-tapas 0.2.1 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "rspec-tapas".freeze
|
9
|
-
s.version = "0.2.
|
9
|
+
s.version = "0.2.1"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["B\u0142a\u017Cej Kosmowski".freeze]
|
14
|
-
s.date = "
|
14
|
+
s.date = "2020-02-04"
|
15
15
|
s.description = "A selection of small rSpec extensions".freeze
|
16
16
|
s.email = "b.kosmowski@selleo.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
@@ -19,7 +19,9 @@ Gem::Specification.new do |s|
|
|
19
19
|
"README.md"
|
20
20
|
]
|
21
21
|
s.files = [
|
22
|
+
".circleci/config.yml",
|
22
23
|
".document",
|
24
|
+
".rspec",
|
23
25
|
"Gemfile",
|
24
26
|
"Gemfile.lock",
|
25
27
|
"LICENSE.txt",
|
@@ -39,11 +41,13 @@ Gem::Specification.new do |s|
|
|
39
41
|
"lib/rspec_tapas/matchers/have_table_row.rb",
|
40
42
|
"lib/rspec_tapas/stub_env.rb",
|
41
43
|
"lib/rspec_tapas/view_page.rb",
|
42
|
-
"rspec-tapas.gemspec"
|
44
|
+
"rspec-tapas.gemspec",
|
45
|
+
"spec/rspec_tapas/matchers/have_table_row_spec.rb",
|
46
|
+
"spec/spec_helper.rb"
|
43
47
|
]
|
44
48
|
s.homepage = "http://github.com/Selleo/rspec-tapas".freeze
|
45
49
|
s.licenses = ["MIT".freeze]
|
46
|
-
s.rubygems_version = "
|
50
|
+
s.rubygems_version = "3.0.3".freeze
|
47
51
|
s.summary = "A selection of small rSpec extensions".freeze
|
48
52
|
|
49
53
|
if s.respond_to? :specification_version then
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'have_table_row matcher' do
|
4
|
+
context 'when columns are described by name' do
|
5
|
+
context 'when table contains expected data' do
|
6
|
+
it 'ensures that page have table with given data' do
|
7
|
+
page = Capybara.string <<-HTML
|
8
|
+
<table>
|
9
|
+
<thead>
|
10
|
+
<tr><th>Name</th><th>Age</th></tr>
|
11
|
+
</thead>
|
12
|
+
<tbody>
|
13
|
+
<tr><td>John</td><td>27</td></tr>
|
14
|
+
</tbody>
|
15
|
+
</table>
|
16
|
+
HTML
|
17
|
+
|
18
|
+
expect(page).to have_table_row('Name' => 'John', 'Age' => 27)
|
19
|
+
expect(page).to have_table_row(0 => 'John', 1 => 27)
|
20
|
+
expect(page).to have_table_row('John', 27)
|
21
|
+
expect(page).to have_table_row(have_content('oh'), 27)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when table does not contain expected data' do
|
26
|
+
context 'when given column does not exist' do
|
27
|
+
it 'returns error message indicating which column is missing' do
|
28
|
+
page = Capybara.string <<-HTML
|
29
|
+
<table>
|
30
|
+
<thead>
|
31
|
+
<tr><th>Age</th></tr>
|
32
|
+
</thead>
|
33
|
+
<tbody>
|
34
|
+
<tr><td>12</td></tr>
|
35
|
+
</tbody>
|
36
|
+
</table>
|
37
|
+
HTML
|
38
|
+
|
39
|
+
page_without_headers = Capybara.string <<-HTML
|
40
|
+
<table>
|
41
|
+
<tbody>
|
42
|
+
<tr><td>12</td></tr>
|
43
|
+
</tbody>
|
44
|
+
</table>
|
45
|
+
HTML
|
46
|
+
|
47
|
+
expect do
|
48
|
+
expect(page).to have_table_row('Name' => 'John', 'Age' => 27)
|
49
|
+
end.to fail_with('Could not find columns: Name')
|
50
|
+
|
51
|
+
expect do
|
52
|
+
expect(page_without_headers).to have_table_row('Name' => 'John', 'Age' => 27)
|
53
|
+
end.to fail_with('Could not find columns: Name, Age')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when row with given data does not exist' do
|
58
|
+
it 'returns error messages indicating which row is missing' do
|
59
|
+
page = Capybara.string <<-HTML
|
60
|
+
<table>
|
61
|
+
<thead>
|
62
|
+
<tr><th>Name</th><th>Age</th></tr>
|
63
|
+
</thead>
|
64
|
+
<tbody>
|
65
|
+
<tr><td>Adam</td><td>24</td></tr>
|
66
|
+
<tr><td>Bartosz</td><td>12</td></tr>
|
67
|
+
</tbody>
|
68
|
+
</table>
|
69
|
+
HTML
|
70
|
+
|
71
|
+
expect do
|
72
|
+
expect(page).to have_table_row('Age' => 27, 'Name' => 'John')
|
73
|
+
end.to fail_with('Row with Age: 27, Name: John not found')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'when there are two tables' do
|
79
|
+
it 'requires table to be specified' do
|
80
|
+
page = Capybara.string <<-HTML
|
81
|
+
<table id="first-table">
|
82
|
+
<thead>
|
83
|
+
<tr><th><th>Name</th><th>Age</th></tr>
|
84
|
+
</thead>
|
85
|
+
<tbody>
|
86
|
+
<tr><td>John</td><td>27</td></tr>
|
87
|
+
</tbody>
|
88
|
+
</table>
|
89
|
+
<table id="second-table">
|
90
|
+
<thead>
|
91
|
+
<tr><th><th>Name</th><th>Age</th></tr>
|
92
|
+
</thead>
|
93
|
+
<tbody>
|
94
|
+
<tr><td>John</td><td>27</td></tr>
|
95
|
+
</tbody>
|
96
|
+
</table>
|
97
|
+
HTML
|
98
|
+
|
99
|
+
expect do
|
100
|
+
expect(page).to have_table_row('John', 27)
|
101
|
+
end.to fail_with('Ambiguous match, there is more than one table')
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'ensures that page have table with given data' do
|
105
|
+
page = Capybara.string <<-HTML
|
106
|
+
<table id="first-table">
|
107
|
+
<thead>
|
108
|
+
<tr><th><th>Name</th><th>Age</th></tr>
|
109
|
+
</thead>
|
110
|
+
<tbody>
|
111
|
+
<tr><td>John</td><td>27</td></tr>
|
112
|
+
</tbody>
|
113
|
+
</table>
|
114
|
+
<table id="second-table">
|
115
|
+
<thead>
|
116
|
+
<tr><th><th>Name</th><th>Age</th></tr>
|
117
|
+
</thead>
|
118
|
+
<tbody>
|
119
|
+
<tr><td>John</td><td>27</td></tr>
|
120
|
+
</tbody>
|
121
|
+
</table>
|
122
|
+
HTML
|
123
|
+
|
124
|
+
within(page.find('table#second-table')) do
|
125
|
+
expect(page).to have_table_row('John', 27)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'active_support/core_ext/array/extract_options'
|
4
|
+
require 'rspec_tapas/matchers/have_table_row'
|
5
|
+
require 'rspec/matchers/fail_matchers'
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.expect_with :rspec do |expectations|
|
9
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
10
|
+
end
|
11
|
+
|
12
|
+
config.mock_with :rspec do |mocks|
|
13
|
+
mocks.verify_partial_doubles = true
|
14
|
+
end
|
15
|
+
|
16
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
17
|
+
|
18
|
+
config.include RSpecTapas::Matchers
|
19
|
+
config.include RSpec::Matchers::FailMatchers
|
20
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-tapas
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Błażej Kosmowski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: shoulda
|
@@ -88,7 +88,9 @@ extra_rdoc_files:
|
|
88
88
|
- LICENSE.txt
|
89
89
|
- README.md
|
90
90
|
files:
|
91
|
+
- ".circleci/config.yml"
|
91
92
|
- ".document"
|
93
|
+
- ".rspec"
|
92
94
|
- Gemfile
|
93
95
|
- Gemfile.lock
|
94
96
|
- LICENSE.txt
|
@@ -109,6 +111,8 @@ files:
|
|
109
111
|
- lib/rspec_tapas/stub_env.rb
|
110
112
|
- lib/rspec_tapas/view_page.rb
|
111
113
|
- rspec-tapas.gemspec
|
114
|
+
- spec/rspec_tapas/matchers/have_table_row_spec.rb
|
115
|
+
- spec/spec_helper.rb
|
112
116
|
homepage: http://github.com/Selleo/rspec-tapas
|
113
117
|
licenses:
|
114
118
|
- MIT
|
@@ -128,8 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
132
|
- !ruby/object:Gem::Version
|
129
133
|
version: '0'
|
130
134
|
requirements: []
|
131
|
-
|
132
|
-
rubygems_version: 2.6.14
|
135
|
+
rubygems_version: 3.0.3
|
133
136
|
signing_key:
|
134
137
|
specification_version: 4
|
135
138
|
summary: A selection of small rSpec extensions
|