shopify_liquid_test_helper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 78ab883c518d4cb5d8e2bee3c6cb8c4f65781724f3d5e7e093f55b5e108e041c
4
+ data.tar.gz: 1d1d92e1d5e717b655152a320bcbb69cc72eebc111756d0e4f969af1a97c5e45
5
+ SHA512:
6
+ metadata.gz: 6559b4229c6fa3ef893499b7bc4d397d9dc270d840b1b33e9871004b84549857e1e646d272f0c2a9719d0db71f324d5b4eb06940702b126f49f8f9bf1992b3c3
7
+ data.tar.gz: a1aa6a1ed00f58fc7648aec4e625417ad59f2fe9fefd64f93c05535cda798af44d1eeb599439f7cc98ab27d2b89eaa8c2216f04811f4ced877e922aec4101053
data/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # ShopifyLiquidTestHelper
2
+
3
+ ShopifyLiquidTestHelper is a Ruby gem designed to assist in testing Shopify Liquid templates. It provides custom Liquid tags and helper methods that simulate Shopify-specific functionality, making it easier to test your Liquid templates in isolation.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'shopify_liquid_test_helper'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```
16
+ $ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```
22
+ $ gem install shopify_liquid_test_helper
23
+ ```
24
+
25
+ ## Usage with RSpec
26
+
27
+ ### Setup
28
+
29
+ In your `spec_helper.rb` or at the beginning of your test file, require and configure the helper:
30
+
31
+ ```ruby
32
+ require 'shopify_liquid_test_helper'
33
+
34
+ RSpec.configure do |config|
35
+ config.before(:each) do
36
+ ShopifyLiquidTestHelper.register_custom_tags
37
+ end
38
+ end
39
+ ```
40
+
41
+ ### Testing Liquid Templates
42
+
43
+ Here are some examples of how you can use ShopifyLiquidTestHelper in your RSpec tests:
44
+
45
+ 1. Testing a simple render tag:
46
+
47
+ ```ruby
48
+ RSpec.describe "Product template" do
49
+ before do
50
+ ShopifyLiquidTestHelper.register_snippet('product_title', '<h1>{{ product.title }}</h1>')
51
+ end
52
+
53
+ it "renders the product title" do
54
+ template = "{% render 'product_title' %}"
55
+ assigns = { 'product' => { 'title' => 'Awesome T-Shirt' } }
56
+ result = ShopifyLiquidTestHelper.render_template(Liquid::Template.parse(template), assigns)
57
+ expect(result).to eq '<h1>Awesome T-Shirt</h1>'
58
+ end
59
+ end
60
+ ```
61
+
62
+ 2. Testing a for loop in a render tag:
63
+
64
+ ```ruby
65
+ RSpec.describe "Collection template" do
66
+ before do
67
+ ShopifyLiquidTestHelper.register_snippet('product_list', '{% for product in products %}{{ product.title }}{% endfor %}')
68
+ end
69
+
70
+ it "renders a list of product titles" do
71
+ template = "{% render 'product_list' for products %}"
72
+ assigns = { 'products' => [{ 'title' => 'Shirt' }, { 'title' => 'Pants' }] }
73
+ result = ShopifyLiquidTestHelper.render_template(Liquid::Template.parse(template), assigns)
74
+ expect(result).to eq 'ShirtPants'
75
+ end
76
+ end
77
+ ```
78
+
79
+ 3. Testing the capture tag:
80
+
81
+ ```ruby
82
+ RSpec.describe "Capture tag" do
83
+ it "captures content into a variable" do
84
+ template = "{% capture my_variable %}Hello, {{ name }}!{% endcapture %}{{ my_variable }}"
85
+ assigns = { 'name' => 'World' }
86
+ result = ShopifyLiquidTestHelper.render_template(Liquid::Template.parse(template), assigns)
87
+ expect(result).to eq 'Hello, World!'
88
+ end
89
+ end
90
+ ```
91
+
92
+ ### Loading Snippets from Directory
93
+
94
+ ShopifyLiquidTestHelper can load snippets from a specific directory. By default, it looks for snippets in a `snippets` directory relative to your current working directory. You can use this feature as follows:
95
+
96
+ 1. Create a `snippets` directory in your project:
97
+
98
+ ```
99
+ mkdir snippets
100
+ ```
101
+
102
+ 2. Add your Liquid snippet files to this directory. For example, create a file named `product_card.liquid`:
103
+
104
+ ```liquid
105
+ <!-- snippets/product_card.liquid -->
106
+ <div class="product-card">
107
+ <h2>{{ product.title }}</h2>
108
+ <p>Price: {{ product.price | money }}</p>
109
+ </div>
110
+ ```
111
+
112
+ 3. In your tests, you can now render this snippet:
113
+
114
+ ```ruby
115
+ RSpec.describe "Product listing" do
116
+ it "renders a product card" do
117
+ template = "{% render 'product_card' %}"
118
+ assigns = {
119
+ 'product' => {
120
+ 'title' => 'Awesome T-Shirt',
121
+ 'price' => 1999
122
+ }
123
+ }
124
+ result = ShopifyLiquidTestHelper.render_template(Liquid::Template.parse(template), assigns)
125
+ expect(result).to include('Awesome T-Shirt')
126
+ expect(result).to include('Price: $19.99')
127
+ end
128
+ end
129
+ ```
130
+
131
+ ShopifyLiquidTestHelper will automatically load the `product_card` snippet from the `snippets` directory when you use the `render` tag in your Liquid template.
132
+
133
+ ### Customizing the Snippets Directory
134
+
135
+ If your snippets are located in a different directory, you can specify the path when initializing ShopifyLiquidTestHelper:
136
+
137
+ ```ruby
138
+ ShopifyLiquidTestHelper.snippets_dir = 'path/to/your/snippets'
139
+ ```
140
+
141
+ This allows you to organize your snippets in a way that best fits your project structure.
142
+
143
+ ### Combining Registered and File-based Snippets
144
+
145
+ You can use both registered snippets (using `ShopifyLiquidTestHelper.register_snippet`) and file-based snippets in the same test suite. ShopifyLiquidTestHelper will first check for registered snippets, and if not found, it will look for a matching file in the snippets directory.
146
+
147
+ ```ruby
148
+ RSpec.describe "Mixed snippet sources" do
149
+ before do
150
+ ShopifyLiquidTestHelper.register_snippet('inline_snippet', 'This is an inline snippet')
151
+ end
152
+
153
+ it "renders both registered and file-based snippets" do
154
+ template = """
155
+ {% render 'inline_snippet' %}
156
+ {% render 'product_card' %}
157
+ """
158
+ assigns = {
159
+ 'product' => {
160
+ 'title' => 'Cool Product',
161
+ 'price' => 2499
162
+ }
163
+ }
164
+ result = ShopifyLiquidTestHelper.render_template(Liquid::Template.parse(template), assigns)
165
+ expect(result).to include('This is an inline snippet')
166
+ expect(result).to include('Cool Product')
167
+ expect(result).to include('Price: $24.99')
168
+ end
169
+ end
170
+ ```
171
+
172
+ ### Advanced Usage
173
+
174
+ For more complex scenarios, you can create helper methods in your specs to simplify template rendering:
175
+
176
+ ```ruby
177
+ def render_template(template, assigns = {})
178
+ Liquid::Template.parse(template).render(assigns)
179
+ end
180
+
181
+ RSpec.describe "Complex template" do
182
+ it "renders a complex structure" do
183
+ template = """
184
+ {% render 'header' %}
185
+ {% for product in collection.products %}
186
+ {% render 'product_card' %}
187
+ {% endfor %}
188
+ {% render 'footer' %}
189
+ """
190
+ assigns = {
191
+ 'collection' => {
192
+ 'products' => [
193
+ { 'title' => 'Product 1', 'price' => 19.99 },
194
+ { 'title' => 'Product 2', 'price' => 24.99 }
195
+ ]
196
+ }
197
+ }
198
+ result = render_template(template, assigns)
199
+ expect(result).to include('Product 1')
200
+ expect(result).to include('Product 2')
201
+ expect(result).to include('19.99')
202
+ expect(result).to include('24.99')
203
+ end
204
+ end
205
+ ```
206
+
207
+ This gem allows you to test your Shopify Liquid templates thoroughly, ensuring they render correctly with various inputs and scenarios.
208
+
209
+ ## Contributing
210
+
211
+ Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/shopify_liquid_test_helper.
212
+
213
+ ## License
214
+
215
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,14 @@
1
+ module ShopifyLiquidTestHelper
2
+ class CaptureTag < Liquid::Block
3
+ def initialize(tag_name, markup, tokens)
4
+ super
5
+ @variable_name = markup.strip
6
+ end
7
+
8
+ def render(context)
9
+ result = super
10
+ context.scopes.last[@variable_name] = result
11
+ ''
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,107 @@
1
+ module ShopifyLiquidTestHelper
2
+ class RenderTag < Liquid::Tag
3
+ SYNTAX = /(#{Liquid::QuotedFragment}+)(\s+(?:with|for)\s+(#{Liquid::QuotedFragment}+))?(\s+as\s+(#{Liquid::QuotedFragment}+))?/o
4
+
5
+ def initialize(tag_name, markup, tokens)
6
+ super
7
+ parse_markup(markup)
8
+ @params = extract_params(markup)
9
+ end
10
+
11
+ def render(context)
12
+ snippet_name = resolve_snippet_name(context)
13
+ snippet = fetch_snippet(snippet_name)
14
+
15
+ temp_context = create_isolated_context(context)
16
+ variable = resolve_variable(context)
17
+
18
+ if @for_loop
19
+ render_for_loop(snippet, variable, temp_context)
20
+ else
21
+ render_with_variable(snippet, variable, temp_context)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def parse_markup(markup)
28
+ unless markup =~ SYNTAX
29
+ raise Liquid::SyntaxError,
30
+ "Syntax Error in 'render' - Valid syntax: render 'snippet' [with object|for array] [as alias]"
31
+ end
32
+
33
+ @snippet_name = ::Regexp.last_match(1)
34
+ @variable_name = ::Regexp.last_match(3)
35
+ @alias = ::Regexp.last_match(5)
36
+ @for_loop = ::Regexp.last_match(2) =~ /\s+for\s+/
37
+ end
38
+
39
+ def extract_params(markup)
40
+ params = {}
41
+ markup.scan(Liquid::TagAttributes) { |key, value| params[key] = value }
42
+ params
43
+ end
44
+
45
+ def resolve_snippet_name(context)
46
+ snippet_name = context[@snippet_name] || @snippet_name
47
+ snippet_name.gsub(/['"]/, '')
48
+ end
49
+
50
+ def fetch_snippet(snippet_name)
51
+ snippet = ShopifyLiquidTestHelper.get_snippet(snippet_name)
52
+ raise Liquid::SyntaxError, "Unknown snippet '#{snippet_name}'" unless snippet
53
+
54
+ snippet
55
+ end
56
+
57
+ def resolve_variable(context)
58
+ @variable_name ? context[@variable_name] : nil
59
+ end
60
+
61
+ def render_for_loop(snippet, array, context)
62
+ return unless array.respond_to?(:each)
63
+
64
+ array.each_with_index.map do |item, index|
65
+ item_context = create_item_context(context, item, index, array.size)
66
+ Liquid::Template.parse(snippet).render(item_context)
67
+ end.join
68
+ end
69
+
70
+ def create_item_context(context, item, index, array_size)
71
+ item_context = context.new_isolated_subcontext
72
+ item_context[@alias || 'item'] = item
73
+
74
+ item_context['forloop'] = {
75
+ 'first' => index.zero?,
76
+ 'index' => index + 1,
77
+ 'index0' => index,
78
+ 'last' => index == array_size - 1,
79
+ 'length' => array_size,
80
+ 'rindex' => array_size - index,
81
+ 'rindex0' => array_size - index - 1
82
+ }
83
+
84
+ @params.each do |key, value|
85
+ item_context[key] = context[value] || context.evaluate(value) || value
86
+ end
87
+
88
+ item_context
89
+ end
90
+
91
+ def render_with_variable(snippet, variable, context)
92
+ context[@alias || 'object'] = variable if @variable_name
93
+
94
+ @params.each do |key, value|
95
+ context[key] = context[value] || context.evaluate(value) || value
96
+ end
97
+
98
+ Liquid::Template.parse(snippet).render(context)
99
+ end
100
+
101
+ def create_isolated_context(context)
102
+ new_context = context.new_isolated_subcontext
103
+ @params.each { |key, value| new_context[key] = context[value] || context.evaluate(value) || value }
104
+ new_context
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,50 @@
1
+ require 'liquid'
2
+ require 'shopify_liquid_test_helper/render_tag'
3
+ require 'shopify_liquid_test_helper/capture_tag'
4
+
5
+ module ShopifyLiquidTestHelper
6
+ class << self
7
+ attr_accessor :snippets_dir
8
+
9
+ def parse_template(template_name)
10
+ Liquid::Template.parse(File.read(template_name))
11
+ end
12
+
13
+ def render_template(template, assigns)
14
+ template.render(assigns).strip
15
+ end
16
+
17
+ def register_custom_tags
18
+ Liquid::Template.register_tag('render', RenderTag)
19
+ Liquid::Template.register_tag('capture', CaptureTag)
20
+ end
21
+
22
+ def register_snippet(name, content)
23
+ snippets[name] = content
24
+ end
25
+
26
+ def get_snippet(name)
27
+ snippets[name] || load_snippet(name)
28
+ end
29
+
30
+ private
31
+
32
+ def snippets
33
+ @snippets ||= {}
34
+ end
35
+
36
+ def load_snippet(name)
37
+ snippet_path = File.join(snippets_dir || 'snippets', "#{name}.liquid")
38
+ if File.exist?(snippet_path)
39
+ snippet = File.read(snippet_path)
40
+ snippets[name] = snippet
41
+ else
42
+ puts "Snippet not found: #{snippet_path}"
43
+ nil
44
+ end
45
+ end
46
+ end
47
+
48
+ # デフォルトのsnippetsディレクトリを設定
49
+ @snippets_dir = 'snippets'
50
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ShopifyLiquidTestHelper do
4
+ before(:all) do
5
+ ShopifyLiquidTestHelper.register_custom_tags
6
+ ShopifyLiquidTestHelper.register_snippet('simple', 'Hello, {{ name }}!')
7
+ ShopifyLiquidTestHelper.register_snippet('for_loop', 'Item: {{ item }}')
8
+ ShopifyLiquidTestHelper.register_snippet('with_object', 'Name: {{ object.name }}')
9
+ end
10
+
11
+ def render(template, assigns = {})
12
+ Liquid::Template.parse(template).render(assigns)
13
+ end
14
+
15
+ describe 'render tag' do
16
+ it 'renders a simple snippet' do
17
+ template = "{% render 'simple', name: 'World' %}"
18
+ expect(render(template)).to eq 'Hello, World!'
19
+ end
20
+
21
+ it 'renders a snippet with a for loop' do
22
+ template = "{% render 'for_loop' for items as item %}"
23
+ assigns = { 'items' => %w[A B C] }
24
+ expect(render(template, assigns)).to eq 'Item: AItem: BItem: C'
25
+ end
26
+
27
+ it 'renders a snippet with an object' do
28
+ template = "{% render 'with_object' with user as object %}"
29
+ assigns = { 'user' => { 'name' => 'John' } }
30
+ expect(render(template, assigns)).to eq 'Name: John'
31
+ end
32
+
33
+ it 'does not allow access to variables outside the snippet' do
34
+ ShopifyLiquidTestHelper.register_snippet('isolated', '{{ outside_var }}')
35
+ template = "{% assign outside_var = 'Outside' %}{% render 'isolated' %}"
36
+ expect(render(template)).to eq ''
37
+ end
38
+
39
+ it 'provides all forloop variables in for loop rendering' do
40
+ ShopifyLiquidTestHelper.register_snippet('forloop_vars',
41
+ '{{ forloop.index }},{{ forloop.index0 }},{{ forloop.first }},{{ forloop.last }},{{ forloop.length }},{{ forloop.rindex }},{{ forloop.rindex0 }}|')
42
+ template = "{% render 'forloop_vars' for items as item %}"
43
+ assigns = { 'items' => %w[A B C] }
44
+ expect(render(template, assigns)).to eq '1,0,true,false,3,3,2|2,1,false,false,3,2,1|3,2,false,true,3,1,0|'
45
+ end
46
+
47
+ it 'allows using an alias for the rendered variable' do
48
+ template = "{% render 'simple' with 'Alias' as name %}"
49
+ expect(render(template)).to eq 'Hello, Alias!'
50
+ end
51
+
52
+ it 'does not pollute the outer scope' do
53
+ template = "{% render 'simple' with 'Inner' as name %}{{ name }}"
54
+ assigns = { 'name' => 'Outer' }
55
+ expect(render(template, assigns)).to eq 'Hello, Inner!Outer'
56
+ end
57
+ end
58
+
59
+ describe 'capture tag' do
60
+ it 'captures content into a variable' do
61
+ template = "{% capture my_variable %}Hello, Capture!{% endcapture %}{{ my_variable }}"
62
+ expect(render(template)).to eq 'Hello, Capture!'
63
+ end
64
+
65
+ it 'captures complex content with Liquid logic' do
66
+ template = "{% capture complex %}{% for i in (1..3) %}{{ i }}{% endfor %}{% endcapture %}{{ complex }}"
67
+ expect(render(template)).to eq '123'
68
+ end
69
+
70
+ it 'overwrites previously captured variables' do
71
+ template = "{% capture var %}First{% endcapture %}{% capture var %}Second{% endcapture %}{{ var }}"
72
+ expect(render(template)).to eq 'Second'
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,7 @@
1
+ require 'shopify_liquid_test_helper'
2
+
3
+ RSpec.configure do |config|
4
+ config.before(:all) do
5
+ ShopifyLiquidTestHelper.register_custom_tags
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shopify_liquid_test_helper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ken Takagiwa
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-08-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: liquid
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ description: This gem provides helper methods and custom tags for testing Shopify
56
+ Liquid templates
57
+ email:
58
+ - ugw.gi.world@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - README.md
64
+ - Rakefile
65
+ - lib/shopify_liquid_test_helper.rb
66
+ - lib/shopify_liquid_test_helper/capture_tag.rb
67
+ - lib/shopify_liquid_test_helper/render_tag.rb
68
+ - spec/shopify_liquid_test_helper_spec.rb
69
+ - spec/spec_helper.rb
70
+ homepage: https://github.com/yourusername/shopify_liquid_test_helper
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubygems_version: 3.3.7
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: A helper for testing Shopify Liquid templates
93
+ test_files: []