Тестирование содержимого массива внутри хеша

В Rspec я тестирую хэш, содержащий такой массив:

subject { described_class.call(build: build_one, user:)

it 'returns the correct data' do
  response = subject

  expected_response = {
    id: build_one.id,
    status: {
      key: 'active',
      name: 'Active'
    },
    build_type: 'SystemBuild',
    calculated_type_id: CalculatedType.standard.id,
    build_time: build_one.build_time,
    summary: 'Lorem ipsum dolor sit amet...',
    data: [
      {id: '1', name: '', parent: ''},
      {id: '1.1', name: 'Calc type 1', parent: '1'},
      {id: '1.2', name: 'Calc type 2', parent: '1'},
      {id: '1.3', name: 'Calc type 3', parent: '1'},
      {id: '1.1.1', name: 'Value 1', parent: '1.1'},
      {id: '1.1.2', name: 'Value 2', parent: '1.1'},
      {id: '1.2.1', name: 'Value 3', parent: '1.2'},
      {id: '1.3.1', name: 'Value 4', parent: '1.3'},
      {id: '1.3.2', name: 'Value 5', parent: '1.3'},
      {id: '1.3.3', name: 'Value 6', parent: '1.3'}
    ]
  }

  expect(response).to match(expected_response)
end

Моя проблема в том, что массив data не обязательно находится в том же порядке, как я написал в expected_response.

Я, конечно, мог бы изменить порядок в expected_response, но я не хочу его ограничивать таким образом. Дело в том, что для приложения порядок массива вообще не имеет значения, и изменение других частей приложения может изменить порядок. Важно лишь то, чтобы в массиве присутствовали все элементы.

Когда я запускаю тест, я получаю следующее:

Diff:

 :build_time: 2024-06-22 10:17:55.0000000000 -0700,
 :build_type: "SystemType",
 :calculated_type_id: 3,
 :id => 234,
-:data => [{:id=>"1", :name=>"", :parent=>""}, {:id=>"1.1", :name=>"Calc type 1", :parent=>"1"}, {:id=>"1.2", :name=>"Calc type 2", :parent=>"1"}, {:id=>"1.3", :name=>"Calc type 3", :parent=>"1"}, {:id=>"1.1.1", :name=>"Value 1", :parent=>"1.1"}, {:id=>"1.1.2", :name=>"Value 2", :parent=>"1.1"}, {:id=>"1.2.1", :name=>"Value 3", :parent=>"1.2"}, {:id=>"1.3.1", :name=>"Value 4", :parent=>"1.3"}, {:id=>"1.3.2", :name=>"Value 5", :parent=>"1.3"}, {:id=>"1.3.3", :name=>"Value 6", :parent=>"1.3"}]
+:data => [{:id=>"1", :name=>"", :parent=>""}, {:id=>"1.1", :name=>"Calc type 1", :parent=>"1"}, {:id=>"1.2", :name=>"Calc type 2", :parent=>"1"}, {:id=>"1.3", :name=>"Calc type 3", :parent=>"1"}, {:id=>"1.1.1", :name=>"Value 1", :parent=>"1.1"}, {:id=>"1.2.1", :name=>"Value 3", :parent=>"1.2"}, {:id=>"1.3.2", :name=>"Value 5", :parent=>"1.3"}, {:id=>"1.1.2", :name=>"Value 2", :parent=>"1.1"}, {:id=>"1.3.1", :name=>"Value 4", :parent=>"1.3"}, {:id=>"1.3.3", :name=>"Value 6", :parent=>"1.3"}]
 :status => {:key=>"active", :name=>"Active"},
 :summary => "Lorem ipsum dolor sit amet..."

Я думал, что match(...) проигнорирует порядок массива data и просто проверит существование всех элементов. Есть ли способ сделать это без необходимости проверять каждый элемент хеша?

🤔 А знаете ли вы, что...
Фреймворк обеспечивает поддержку многоязычности и интернационализации (I18n).


1
79
3

Ответы:

Если порядок для вас не имеет значения, я бы просто отсортировал массивы по переменным expected_response и response одинаково:

expected_response[:data] = expected_response[:data].sort_by{|x| x[:id]}
response[:data] = response[:data].sort_by{|x| x[:id]}
expect(response).to match(expected_response)

Решено

При использовании match со структурой данных (массивом или хешем) вы можете использовать другие средства сопоставления RSpec внутри этой структуры, например содержит_точно:

let(:expected) do
  {
    data: contain_exactly(1, 2, 3)
  }
end

it 'matches' do
  expect({ data: [2, 3, 1] }).to match(expected)
end

Вы можете использовать сопоставитель contains_exactly. Просто примените его в ожидаемом ответе таким образом

expected_response = {
  id: 10,
  status: 'ok',
  data: contain_exactly(
    { id: 1 },
    { id: 2 },
  ),
}

response = {
  status: 'ok',
  data: [
    { id: 2 },
    { id: 1 },
  ],
  id: 10,
}

expect(response).to match expected_response

Или примените match_array. В примере выше это будет выглядеть так match_array([{id: 1}, {id: 2}])

Оба сопоставителя игнорируют порядок массива