From 0097e82a9f4245fdc87bf382c0d069d51fa6fc00 Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Thu, 23 Jun 2022 15:00:27 -0400 Subject: [PATCH 1/3] WIP to use offline tokens instead of online --- web/app/controllers/graphql_controller.rb | 19 --- web/app/controllers/products_controller.rb | 16 +++ web/app/jobs/app_uninstalled_job.rb | 2 - web/app/models/user.rb | 9 -- web/app/services/application_service.rb | 5 + web/app/services/product_creator.rb | 115 ++++++++++++++++++ web/config/initializers/shopify_app.rb | 1 - web/config/routes.rb | 5 +- web/db/migrate/20220609125828_create_users.rb | 16 --- ...609125829_add_user_access_scopes_column.rb | 5 - web/db/schema.rb | 12 +- .../controllers/graphql_controller_test.rb | 113 ----------------- web/test/controllers/home_controller_test.rb | 9 -- .../controllers/products_controller_test.rb | 38 +++++- web/test/fixtures/users.yml | 5 - web/test/jobs/app_uninstalled_job_test.rb | 12 -- 16 files changed, 174 insertions(+), 208 deletions(-) delete mode 100644 web/app/controllers/graphql_controller.rb delete mode 100644 web/app/models/user.rb create mode 100644 web/app/services/application_service.rb create mode 100644 web/app/services/product_creator.rb delete mode 100644 web/db/migrate/20220609125828_create_users.rb delete mode 100644 web/db/migrate/20220609125829_add_user_access_scopes_column.rb delete mode 100644 web/test/controllers/graphql_controller_test.rb delete mode 100644 web/test/fixtures/users.yml diff --git a/web/app/controllers/graphql_controller.rb b/web/app/controllers/graphql_controller.rb deleted file mode 100644 index 9a4c471..0000000 --- a/web/app/controllers/graphql_controller.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -class GraphqlController < AuthenticatedController - def proxy - response = ShopifyAPI::Utils::GraphqlProxy.proxy_query( - headers: request.headers.to_h, - body: request.body.read - ) - - render(json: response.body, status: response.code.to_i) - rescue => e - message = "Failed to run GraphQL proxy query: #{e.message}" - - code = e.is_a?(ShopifyAPI::Errors::HttpResponseError) ? e.code : 500 - - logger.info(message) - render(json: message, status: code) - end -end diff --git a/web/app/controllers/products_controller.rb b/web/app/controllers/products_controller.rb index d906180..ea03630 100644 --- a/web/app/controllers/products_controller.rb +++ b/web/app/controllers/products_controller.rb @@ -4,4 +4,20 @@ class ProductsController < AuthenticatedController def count render(json: ShopifyAPI::Product.count.body) end + + def create + ProductCreator.call(count: 5) + + success = true + error = nil + status_code = 200 + rescue => e + success = false + error = e.message + status_code = e.is_a?(ShopifyAPI::Errors::HttpResponseError) ? e.code : 500 + + logger.info("Failed to create products: #{error}") + ensure + render(json: {success: success, error: error}, status: status_code) + end end diff --git a/web/app/jobs/app_uninstalled_job.rb b/web/app/jobs/app_uninstalled_job.rb index e2a46d4..4fbc1bd 100644 --- a/web/app/jobs/app_uninstalled_job.rb +++ b/web/app/jobs/app_uninstalled_job.rb @@ -18,8 +18,6 @@ def perform(topic:, shop_domain:, webhook:) end logger.info("#{self.class} started for shop '#{shop_domain}'") - users = User.where(shopify_domain: shop_domain) - users.each(&:destroy) shop.destroy end end diff --git a/web/app/models/user.rb b/web/app/models/user.rb deleted file mode 100644 index 2ed254a..0000000 --- a/web/app/models/user.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -class User < ActiveRecord::Base - include ShopifyApp::UserSessionStorageWithScopes - - def api_version - ShopifyApp.configuration.api_version - end -end diff --git a/web/app/services/application_service.rb b/web/app/services/application_service.rb new file mode 100644 index 0000000..79ed695 --- /dev/null +++ b/web/app/services/application_service.rb @@ -0,0 +1,5 @@ +class ApplicationService + def self.call(*args, **kwargs, &block) + new(*args, **kwargs, &block).call + end +end diff --git a/web/app/services/product_creator.rb b/web/app/services/product_creator.rb new file mode 100644 index 0000000..86bee86 --- /dev/null +++ b/web/app/services/product_creator.rb @@ -0,0 +1,115 @@ +class ProductCreator < ApplicationService + attr_reader :count + + CREATE_PRODUCTS_MUTATION = <<~'QUERY' + mutation populateProduct($input: ProductInput!) { + productCreate(input: $input) { + product { + id + } + } + } + QUERY + + def initialize(count:, session: ShopifyAPI::Context.active_session) + @count = count + @session = session + end + + def call + client = ShopifyAPI::Clients::Graphql::Admin.new(session: @session) + + for i in 1..count + client.query( + query: CREATE_PRODUCTS_MUTATION, + variables: { + input: { + title: random_title, + variants: [{ price: random_price }], + } + } + ) + end + end + + private + + def random_title + adjective = ADJECTIVES[rand(ADJECTIVES.size)] + noun = NOUNS[rand(NOUNS.size)] + + "#{adjective} #{noun}" + end + + def random_price + (100.0 + rand(1000)) / 100 + end + + ADJECTIVES = [ + "autumn", + "hidden", + "bitter", + "misty", + "silent", + "empty", + "dry", + "dark", + "summer", + "icy", + "delicate", + "quiet", + "white", + "cool", + "spring", + "winter", + "patient", + "twilight", + "dawn", + "crimson", + "wispy", + "weathered", + "blue", + "billowing", + "broken", + "cold", + "damp", + "falling", + "frosty", + "green", + "long", + ] + + NOUNS = [ + "waterfall", + "river", + "breeze", + "moon", + "rain", + "wind", + "sea", + "morning", + "snow", + "lake", + "sunset", + "pine", + "shadow", + "leaf", + "dawn", + "glitter", + "forest", + "hill", + "cloud", + "meadow", + "sun", + "glade", + "bird", + "brook", + "butterfly", + "bush", + "dew", + "dust", + "field", + "fire", + "flower", + ] +end diff --git a/web/config/initializers/shopify_app.rb b/web/config/initializers/shopify_app.rb index d8b7d6c..80f2917 100644 --- a/web/config/initializers/shopify_app.rb +++ b/web/config/initializers/shopify_app.rb @@ -14,7 +14,6 @@ config.after_authenticate_job = false config.api_version = ShopifyAPI::AdminVersions::LATEST_SUPPORTED_ADMIN_VERSION config.shop_session_repository = "Shop" - config.user_session_repository = "User" config.reauth_on_access_scope_changes = true diff --git a/web/config/routes.rb b/web/config/routes.rb index e6b2b63..73d657b 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -8,9 +8,8 @@ # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html - get "/api/products-count", to: "products#count" - - post "/api/graphql", to: "graphql#proxy" + get "/api/products/count", to: "products#count" + get "/api/products/create", to: "products#create" # Any other routes will just render the react app match "*path" => "home#index", via: [:get, :post] diff --git a/web/db/migrate/20220609125828_create_users.rb b/web/db/migrate/20220609125828_create_users.rb deleted file mode 100644 index e8261b4..0000000 --- a/web/db/migrate/20220609125828_create_users.rb +++ /dev/null @@ -1,16 +0,0 @@ -class CreateUsers < ActiveRecord::Migration[7.0] - def self.up - create_table :users do |t| - t.bigint :shopify_user_id, null: false - t.string :shopify_domain, null: false - t.string :shopify_token, null: false - t.timestamps - end - - add_index :users, :shopify_user_id, unique: true - end - - def self.down - drop_table :users - end -end diff --git a/web/db/migrate/20220609125829_add_user_access_scopes_column.rb b/web/db/migrate/20220609125829_add_user_access_scopes_column.rb deleted file mode 100644 index 79a766e..0000000 --- a/web/db/migrate/20220609125829_add_user_access_scopes_column.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddUserAccessScopesColumn < ActiveRecord::Migration[7.0] - def change - add_column :users, :access_scopes, :string - end -end diff --git a/web/db/schema.rb b/web/db/schema.rb index b943a35..e9fe5e2 100644 --- a/web/db/schema.rb +++ b/web/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_06_09_125829) do +ActiveRecord::Schema[7.0].define(version: 2022_06_09_125631) do create_table "shops", force: :cascade do |t| t.string "shopify_domain", null: false t.string "shopify_token", null: false @@ -20,14 +20,4 @@ t.index ["shopify_domain"], name: "index_shops_on_shopify_domain", unique: true end - create_table "users", force: :cascade do |t| - t.bigint "shopify_user_id", null: false - t.string "shopify_domain", null: false - t.string "shopify_token", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "access_scopes" - t.index ["shopify_user_id"], name: "index_users_on_shopify_user_id", unique: true - end - end diff --git a/web/test/controllers/graphql_controller_test.rb b/web/test/controllers/graphql_controller_test.rb deleted file mode 100644 index 4f4f56d..0000000 --- a/web/test/controllers/graphql_controller_test.rb +++ /dev/null @@ -1,113 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -class GraphqlControllerTestTest < ActionDispatch::IntegrationTest - # From fixture data - KNOWN_SHOP = "regular-shop.myshopify.com" - - USER_ID = "1" - - JWT_PAYLOAD = { - iss: "https://#{KNOWN_SHOP}/admin", - dest: "https://#{KNOWN_SHOP}", - aud: ShopifyAPI::Context.api_key, - sub: USER_ID, - exp: (Time.now + 1.days).to_i, - nbf: 1234, - iat: 1234, - jti: "4321", - sid: "abc123", - } - - SESSION = ShopifyAPI::Auth::Session.new( - shopify_session_id: "#{KNOWN_SHOP}_#{USER_ID}", - shop: KNOWN_SHOP, - is_online: true, - access_token: "access-token", - ) - - test "makes successful request" do - response_body = { data: "GraphQL response" } - token = JWT.encode(JWT_PAYLOAD, ShopifyAPI::Context.api_secret_key, "HS256") - stub_request(:post, "https://regular-shop.myshopify.com/admin/api/2022-04/graphql.json") - .with( - body: JSON.dump({ query: "GraphQL query", variables: nil }), - headers: { "X-Shopify-Access-Token" => "access-token" } - ) - .to_return(status: 200, body: JSON.dump(response_body)) - - ShopifyAPI::Utils::SessionUtils.stub(:load_current_session, SESSION) do - post "/api/graphql", - as: :json, - params: { query: "GraphQL query" }, - xhr: true, - headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } - - assert_response :success - assert_match "application/json", @response.headers["Content-Type"] - assert_equal(JSON.dump(response_body), @response.body) - end - end - - test "propagates errors to client side" do - token = JWT.encode(JWT_PAYLOAD, ShopifyAPI::Context.api_secret_key, "HS256") - stub_request(:post, "https://regular-shop.myshopify.com/admin/api/2022-04/graphql.json") - .with( - body: JSON.dump({ query: "GraphQL query", variables: nil }), - headers: { "X-Shopify-Access-Token" => "access-token" } - ) - .to_return(status: 500) - - ShopifyAPI::Utils::SessionUtils.stub(:load_current_session, SESSION) do - post "/api/graphql", - as: :json, - params: { query: "GraphQL query" }, - xhr: true, - headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } - - assert_response 500 - assert_match "application/json", @response.headers["Content-Type"] - end - end - - test "responds with re-auth headers if no session is available" do - token = JWT.encode(JWT_PAYLOAD, ShopifyAPI::Context.api_secret_key, "HS256") - - ShopifyAPI::Utils::SessionUtils.stub(:load_current_session, nil) do - post "/api/graphql", - as: :json, - params: { query: "GraphQL query" }, - xhr: true, - headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } - - assert_response 401 - assert_match "1", @response.headers["X-Shopify-API-Request-Failure-Reauthorize"] - assert_match "/api/auth?shop=#{KNOWN_SHOP}", @response.headers["X-Shopify-API-Request-Failure-Reauthorize-Url"] - end - end - - test "responds with re-auth headers if session has expired" do - payload = JWT_PAYLOAD.clone - payload[:exp] = (Time.now - 1.hour).to_i - token = JWT.encode(payload, ShopifyAPI::Context.api_secret_key, "HS256") - stub_request(:post, "https://regular-shop.myshopify.com/admin/api/2022-04/graphql.json") - .with( - body: JSON.dump({ query: "GraphQL query", variables: nil }), - headers: { "X-Shopify-Access-Token" => "access-token" } - ) - .to_return(status: 401) - - ShopifyAPI::Utils::SessionUtils.stub(:load_current_session, SESSION) do - post "/api/graphql", - as: :json, - params: { query: "GraphQL query" }, - xhr: true, - headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } - - assert_response 401 - assert_match "1", @response.headers["X-Shopify-API-Request-Failure-Reauthorize"] - assert_match "/api/auth?shop=#{KNOWN_SHOP}", @response.headers["X-Shopify-API-Request-Failure-Reauthorize-Url"] - end - end -end diff --git a/web/test/controllers/home_controller_test.rb b/web/test/controllers/home_controller_test.rb index e6a8707..cb69ae6 100644 --- a/web/test/controllers/home_controller_test.rb +++ b/web/test/controllers/home_controller_test.rb @@ -14,15 +14,6 @@ class HomeControllerTestTest < ActionDispatch::IntegrationTest assert_redirected_to(%r{/api/auth\?shop=#{unknown_shop}}) end - test "index does not redirect if shop is installed but there is no online session" do - User.delete_all - - get "/?shop=#{KNOWN_SHOP}" - - assert_response :success - assert_match "text/html", @response.headers["Content-Type"] - end - test "index returns a 200 with HTML if a session exists" do get "/?shop=#{KNOWN_SHOP}" diff --git a/web/test/controllers/products_controller_test.rb b/web/test/controllers/products_controller_test.rb index 0746bc0..8b3d6f1 100644 --- a/web/test/controllers/products_controller_test.rb +++ b/web/test/controllers/products_controller_test.rb @@ -31,7 +31,39 @@ class ProductsControllerTestTest < ActionDispatch::IntegrationTest ShopifyAPI::Context.load_rest_resources(api_version: "2022-04") end - test "makes successful request" do + test "handles creating products" do + token = JWT.encode(JWT_PAYLOAD, ShopifyAPI::Context.api_secret_key, "HS256") + stub = stub_request(:post, "https://regular-shop.myshopify.com/admin/api/2022-04/graphql.json") + .with(headers: { "X-Shopify-Access-Token" => "access-token" }) + .to_return(status: 200, body: JSON.dump({})) + + ShopifyAPI::Utils::SessionUtils.stub(:load_current_session, SESSION) do + get "/api/products/create", + xhr: true, + headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } + + assert_response :success + assert_equal({"success" => true, "error" => nil}, JSON.parse(@response.body)) + end + end + + test "handles product creation errors" do + token = JWT.encode(JWT_PAYLOAD, ShopifyAPI::Context.api_secret_key, "HS256") + stub = stub_request(:post, "https://regular-shop.myshopify.com/admin/api/2022-04/graphql.json") + .with(headers: { "X-Shopify-Access-Token" => "access-token" }) + .to_return(status: 400, body: JSON.dump({errors: "Something went wrong"})) + + ShopifyAPI::Utils::SessionUtils.stub(:load_current_session, SESSION) do + get "/api/products/create", + xhr: true, + headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } + + assert_response :bad_request + assert_equal({"success" => false, "error" => "Something went wrong"}, JSON.parse(@response.body)) + end + end + + test "makes successful count request" do response_body = { count: 10 } token = JWT.encode(JWT_PAYLOAD, ShopifyAPI::Context.api_secret_key, "HS256") stub_request(:get, "https://regular-shop.myshopify.com/admin/api/2022-04/products/count.json") @@ -39,7 +71,7 @@ class ProductsControllerTestTest < ActionDispatch::IntegrationTest .to_return(status: 200, body: JSON.dump(response_body)) ShopifyAPI::Utils::SessionUtils.stub(:load_current_session, SESSION) do - get "/api/products-count", + get "/api/products/count", xhr: true, headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } @@ -53,7 +85,7 @@ class ProductsControllerTestTest < ActionDispatch::IntegrationTest token = JWT.encode(JWT_PAYLOAD, ShopifyAPI::Context.api_secret_key, "HS256") ShopifyAPI::Utils::SessionUtils.stub(:load_current_session, nil) do - get "/api/products-count", + get "/api/products/count", xhr: true, headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } diff --git a/web/test/fixtures/users.yml b/web/test/fixtures/users.yml deleted file mode 100644 index 62062a7..0000000 --- a/web/test/fixtures/users.yml +++ /dev/null @@ -1,5 +0,0 @@ -regular_user: - shopify_domain: "regular-shop.myshopify.com" - shopify_token: "token" - shopify_user_id: 1 - access_scopes: "write_products" diff --git a/web/test/jobs/app_uninstalled_job_test.rb b/web/test/jobs/app_uninstalled_job_test.rb index 6bfa80c..3fba109 100644 --- a/web/test/jobs/app_uninstalled_job_test.rb +++ b/web/test/jobs/app_uninstalled_job_test.rb @@ -3,18 +3,6 @@ require "test_helper" class AppUninstalledJobTest < ActiveJob::TestCase - test "that users for shop_domain in app_uninstalled are deleted from db" do - shop_domain = "regular-shop.myshopify.com" - - users = User.where(shopify_domain: shop_domain) - assert_equal(1, users.count) - - AppUninstalledJob.new.perform(topic: "app_uninstalled", shop_domain: shop_domain, webhook: {}) - - users = User.where(shopify_domain: shop_domain) - assert_equal(0, users.count) - end - test "that shop_domain in app_uninstalled is deleted from db" do shop_domain = "regular-shop.myshopify.com" From dddd015374fbc1e2abd3480c2336c881fcf0fe1a Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Wed, 6 Jul 2022 13:41:31 -0400 Subject: [PATCH 2/3] Update frontend reference --- README.md | 4 ++-- web/frontend | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 50e4fda..a8517b5 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,14 @@ This template combines a number of third party open source tools: - [Rails](https://rubyonrails.org/) builds and tests the backend. - [Vite](https://vitejs.dev/) builds the [React](https://reactjs.org/) frontend. - [React Router](https://reactrouter.com/) is used for routing. We wrap this with file-based routing. -- [React Query](https://react-query.tanstack.com/) queries the GraphQL Admin API. +- [React Query](https://react-query.tanstack.com/) queries the Admin API. These third party tools are complemented by Shopify specific tools to ease app development: - [Shopify API library](https://github.com/Shopify/shopify_api) adds OAuth to the Rails backend. This lets users install the app and grant scope permissions. - [App Bridge React](https://shopify.dev/tools/app-bridge/react-components) adds authentication to API requests in the frontend and renders components outside of the App’s iFrame. - [Polaris React](https://polaris.shopify.com/) is a powerful design system and component library that helps developers build high quality, consistent experiences for Shopify merchants. -- [Custom hooks](https://github.com/Shopify/shopify-frontend-template-react/tree/main/hooks) make authenticated requests to the GraphQL Admin API. +- [Custom hooks](https://github.com/Shopify/shopify-frontend-template-react/tree/main/hooks) make authenticated requests to the Admin API. - [File-based routing](https://github.com/Shopify/shopify-frontend-template-react/blob/main/Routes.jsx) makes creating new pages easier. ## Getting started diff --git a/web/frontend b/web/frontend index e6f3e8e..98451f9 160000 --- a/web/frontend +++ b/web/frontend @@ -1 +1 @@ -Subproject commit e6f3e8ed4da5250ca8890aca27c0c775eb82e67a +Subproject commit 98451f98d897d9c6ad7134fe6bebb64103e1dc09 From 6a92afe6df9e1e830aebf6a4f3b02dd8b3b1ae29 Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Wed, 6 Jul 2022 13:52:07 -0400 Subject: [PATCH 3/3] Fixing rubocop issues --- web/app/controllers/products_controller.rb | 2 +- web/app/services/application_service.rb | 2 ++ web/app/services/product_creator.rb | 7 +++++-- web/test/controllers/products_controller_test.rb | 10 +++++----- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/web/app/controllers/products_controller.rb b/web/app/controllers/products_controller.rb index ea03630..47f6287 100644 --- a/web/app/controllers/products_controller.rb +++ b/web/app/controllers/products_controller.rb @@ -18,6 +18,6 @@ def create logger.info("Failed to create products: #{error}") ensure - render(json: {success: success, error: error}, status: status_code) + render(json: { success: success, error: error }, status: status_code) end end diff --git a/web/app/services/application_service.rb b/web/app/services/application_service.rb index 79ed695..1e34e5d 100644 --- a/web/app/services/application_service.rb +++ b/web/app/services/application_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationService def self.call(*args, **kwargs, &block) new(*args, **kwargs, &block).call diff --git a/web/app/services/product_creator.rb b/web/app/services/product_creator.rb index 86bee86..cb7841e 100644 --- a/web/app/services/product_creator.rb +++ b/web/app/services/product_creator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProductCreator < ApplicationService attr_reader :count @@ -12,6 +14,7 @@ class ProductCreator < ApplicationService QUERY def initialize(count:, session: ShopifyAPI::Context.active_session) + super() @count = count @session = session end @@ -19,14 +22,14 @@ def initialize(count:, session: ShopifyAPI::Context.active_session) def call client = ShopifyAPI::Clients::Graphql::Admin.new(session: @session) - for i in 1..count + (1..count).each do |_i| client.query( query: CREATE_PRODUCTS_MUTATION, variables: { input: { title: random_title, variants: [{ price: random_price }], - } + }, } ) end diff --git a/web/test/controllers/products_controller_test.rb b/web/test/controllers/products_controller_test.rb index 8b3d6f1..295e890 100644 --- a/web/test/controllers/products_controller_test.rb +++ b/web/test/controllers/products_controller_test.rb @@ -33,7 +33,7 @@ class ProductsControllerTestTest < ActionDispatch::IntegrationTest test "handles creating products" do token = JWT.encode(JWT_PAYLOAD, ShopifyAPI::Context.api_secret_key, "HS256") - stub = stub_request(:post, "https://regular-shop.myshopify.com/admin/api/2022-04/graphql.json") + stub_request(:post, "https://regular-shop.myshopify.com/admin/api/2022-04/graphql.json") .with(headers: { "X-Shopify-Access-Token" => "access-token" }) .to_return(status: 200, body: JSON.dump({})) @@ -43,15 +43,15 @@ class ProductsControllerTestTest < ActionDispatch::IntegrationTest headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } assert_response :success - assert_equal({"success" => true, "error" => nil}, JSON.parse(@response.body)) + assert_equal({ "success" => true, "error" => nil }, JSON.parse(@response.body)) end end test "handles product creation errors" do token = JWT.encode(JWT_PAYLOAD, ShopifyAPI::Context.api_secret_key, "HS256") - stub = stub_request(:post, "https://regular-shop.myshopify.com/admin/api/2022-04/graphql.json") + stub_request(:post, "https://regular-shop.myshopify.com/admin/api/2022-04/graphql.json") .with(headers: { "X-Shopify-Access-Token" => "access-token" }) - .to_return(status: 400, body: JSON.dump({errors: "Something went wrong"})) + .to_return(status: 400, body: JSON.dump({ errors: "Something went wrong" })) ShopifyAPI::Utils::SessionUtils.stub(:load_current_session, SESSION) do get "/api/products/create", @@ -59,7 +59,7 @@ class ProductsControllerTestTest < ActionDispatch::IntegrationTest headers: { "HTTP_AUTHORIZATION": "Bearer #{token}" } assert_response :bad_request - assert_equal({"success" => false, "error" => "Something went wrong"}, JSON.parse(@response.body)) + assert_equal({ "success" => false, "error" => "Something went wrong" }, JSON.parse(@response.body)) end end