diff --git a/app/services/neopets/nc_mall.rb b/app/services/neopets/nc_mall.rb index c11fea2e..9795edfd 100644 --- a/app/services/neopets/nc_mall.rb +++ b/app/services/neopets/nc_mall.rb @@ -38,8 +38,20 @@ module Neopets::NCMall uniq end - STYLING_STUDIO_URL = "https://www.neopets.com/np-templates/ajax/stylingstudio/studio.php" def self.load_styles(species_id:, neologin:) + Sync do + tabs = [ + Async { load_styles_tab(species_id:, neologin:, tab: 1) }, + Async { load_styles_tab(species_id:, neologin:, tab: 2) }, + ] + tabs.map(&:wait).flatten(1) + end + end + + private + + STYLING_STUDIO_URL = "https://www.neopets.com/np-templates/ajax/stylingstudio/studio.php" + def self.load_styles_tab(species_id:, neologin:, tab:) Sync do DTIRequests.post( STYLING_STUDIO_URL, @@ -48,7 +60,7 @@ module Neopets::NCMall ["Cookie", "neologin=#{neologin}"], ["X-Requested-With", "XMLHttpRequest"], ], - {tab: 1, mode: "getStyles", species: species_id}.to_query, + {tab:, mode: "getStyles", species: species_id}.to_query, ) do |response| if response.status != 200 raise ResponseNotOK.new(response.status), @@ -60,7 +72,8 @@ module Neopets::NCMall # HACK: styles is a hash, unless it's empty, in which case it's an # array? Weird. Normalize this by converting to hash. - data.fetch(:styles).to_h.values + data.fetch(:styles).to_h.values. + map { |s| s.slice(:oii, :name, :image, :limited) } rescue JSON::ParserError, KeyError raise UnexpectedResponseFormat end @@ -68,8 +81,6 @@ module Neopets::NCMall end end - private - def self.load_page_by_url(url) Sync do DTIRequests.get(url) do |response| diff --git a/spec/services/nc_mall_spec.rb b/spec/services/nc_mall_spec.rb index 96c7ab35..eefea8d0 100644 --- a/spec/services/nc_mall_spec.rb +++ b/spec/services/nc_mall_spec.rb @@ -3,7 +3,7 @@ require_relative '../rails_helper' RSpec.describe Neopets::NCMall, type: :model do describe ".load_styles" do - def stub_styles_request + def stub_styles_request(tab:) stub_request(:post, "https://www.neopets.com/np-templates/ajax/stylingstudio/studio.php"). with( headers: { @@ -12,10 +12,15 @@ RSpec.describe Neopets::NCMall, type: :model do "Cookie": "neologin=STUB_NEOLOGIN", "User-Agent": Rails.configuration.user_agent_for_neopets, }, - body: "mode=getStyles&species=2&tab=1", + body: "mode=getStyles&species=2&tab=#{tab}", ) end + def empty_styles_response + # You'd think styles would be `{}` in this case, but it's `[]`. Huh! + { body: '{"success":true,"styles":[]}' } + end + subject(:styles) do Neopets::NCMall.load_styles( species_id: 2, @@ -24,9 +29,12 @@ RSpec.describe Neopets::NCMall, type: :model do end it "loads current NC styles from the NC Mall" do - stub_styles_request.to_return( + stub_styles_request(tab: 1).to_return( body: '{"success":true,"styles":{"87966":{"oii":87966,"name":"Nostalgic Alien Aisha","image":"https:\/\/images.neopets.com\/items\/nostalgic_alien_aisha.gif","limited":false},"87481":{"oii":87481,"name":"Nostalgic Sponge Aisha","image":"https:\/\/images.neopets.com\/items\/nostalgic_sponge_aisha.gif","limited":false},"90031":{"oii":90031,"name":"Celebratory Anniversary Aisha","image":"https:\/\/images.neopets.com\/items\/624dc08bcf.gif","limited":true},"90050":{"oii":90050,"name":"Nostalgic Tyrannian Aisha","image":"https:\/\/images.neopets.com\/items\/b225e06541.gif","limited":true}}}', ) + stub_styles_request(tab: 2).to_return( + body: '{"success":true,"styles":{"90338":{"oii":90338,"name":"Prismatic Pine: Christmas Aisha","image":"https:\/\/images.neopets.com\/items\/3m182ff5.gif","limited":true,"style":90252},"90348":{"oii":90348,"name":"Prismatic Tinsel: Christmas Aisha","image":"https:\/\/images.neopets.com\/items\/4j29mb91.gif","limited":true,"style":90252}}}' + ) expect(styles).to contain_exactly( { @@ -52,37 +60,50 @@ RSpec.describe Neopets::NCMall, type: :model do name: "Nostalgic Tyrannian Aisha", image: "https://images.neopets.com/items/b225e06541.gif", limited: true, + }, + { + oii: 90338, + name: "Prismatic Pine: Christmas Aisha", + image: "https://images.neopets.com/items/3m182ff5.gif", + limited: true, + }, + { + oii: 90348, + name: "Prismatic Tinsel: Christmas Aisha", + image: "https://images.neopets.com/items/4j29mb91.gif", + limited: true, } ) end it "handles the NC Mall's odd API behavior for zero styles" do - stub_styles_request.to_return( - # You'd think styles would be `{}` in this case, but it's `[]`. Huh! - body: '{"success":true,"styles":[]}', - ) + stub_styles_request(tab: 1).to_return(empty_styles_response) + stub_styles_request(tab: 2).to_return(empty_styles_response) expect(styles).to be_empty end it "raises an error if the request returns a non-200 status" do - stub_styles_request.to_return(status: 400) + stub_styles_request(tab: 1).to_return(status: 400) + stub_styles_request(tab: 2).to_return(empty_styles_response) expect { styles }.to raise_error(Neopets::NCMall::ResponseNotOK) end it "raises an error if the request returns a non-JSON response" do - stub_styles_request.to_return( + stub_styles_request(tab: 1).to_return( body: "Oops, this request failed for some weird reason!", ) + stub_styles_request(tab: 2).to_return(empty_styles_response) expect { styles }.to raise_error(Neopets::NCMall::UnexpectedResponseFormat) end it "raises an error if the request returns unexpected JSON" do - stub_styles_request.to_return( + stub_styles_request(tab: 1).to_return( body: '{"success": false}', ) + stub_styles_request(tab: 2).to_return(empty_styles_response) expect { styles }.to raise_error(Neopets::NCMall::UnexpectedResponseFormat) end