|
|
@@ -0,0 +1,218 @@ |
|
|
|
|
|
require 'rails_helper' |
|
|
|
|
|
|
|
|
|
|
|
RSpec.describe 'TagVersions API', type: :request do |
|
|
|
|
|
let(:member) { create(:user, :member, name: 'version member') } |
|
|
|
|
|
|
|
|
|
|
|
let!(:tag) { create(:tag, name: 'tag_versions_target', category: :general) } |
|
|
|
|
|
let!(:other_tag) { create(:tag, name: 'tag_versions_other', category: :general) } |
|
|
|
|
|
|
|
|
|
|
|
let!(:parent_shared) { create(:tag, name: 'parent_shared', category: :general) } |
|
|
|
|
|
let!(:parent_old) { create(:tag, name: 'parent_old', category: :general) } |
|
|
|
|
|
let!(:parent_new) { create(:tag, name: 'parent_new', category: :general) } |
|
|
|
|
|
let!(:other_parent) { create(:tag, name: 'other_parent', category: :general) } |
|
|
|
|
|
|
|
|
|
|
|
let(:t_v1) { Time.zone.local(2020, 1, 1, 12, 0, 0) } |
|
|
|
|
|
let(:t_v2) { Time.zone.local(2020, 1, 2, 12, 0, 0) } |
|
|
|
|
|
let(:t_other) { Time.zone.local(2020, 1, 3, 12, 0, 0) } |
|
|
|
|
|
|
|
|
|
|
|
def create_tag_version!( |
|
|
|
|
|
tag:, |
|
|
|
|
|
version_no:, |
|
|
|
|
|
event_type:, |
|
|
|
|
|
name:, |
|
|
|
|
|
category:, |
|
|
|
|
|
aliases: [], |
|
|
|
|
|
parent_tags: [], |
|
|
|
|
|
created_by_user:, |
|
|
|
|
|
created_at: |
|
|
|
|
|
) |
|
|
|
|
|
TagVersion.create!( |
|
|
|
|
|
tag: tag, |
|
|
|
|
|
version_no: version_no, |
|
|
|
|
|
event_type: event_type, |
|
|
|
|
|
name: name, |
|
|
|
|
|
category: category, |
|
|
|
|
|
aliases: Array(aliases).join(' '), |
|
|
|
|
|
parent_tag_ids: Array(parent_tags).map(&:id).join(' '), |
|
|
|
|
|
created_by_user: created_by_user, |
|
|
|
|
|
created_at: created_at |
|
|
|
|
|
) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
let!(:v1) do |
|
|
|
|
|
create_tag_version!( |
|
|
|
|
|
tag: tag, |
|
|
|
|
|
version_no: 1, |
|
|
|
|
|
event_type: 'create', |
|
|
|
|
|
name: 'old_tag_name', |
|
|
|
|
|
category: 'general', |
|
|
|
|
|
aliases: ['alias_shared', 'alias_old'], |
|
|
|
|
|
parent_tags: [parent_shared, parent_old], |
|
|
|
|
|
created_by_user: member, |
|
|
|
|
|
created_at: t_v1 |
|
|
|
|
|
) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
let!(:v2) do |
|
|
|
|
|
create_tag_version!( |
|
|
|
|
|
tag: tag, |
|
|
|
|
|
version_no: 2, |
|
|
|
|
|
event_type: 'update', |
|
|
|
|
|
name: 'new_tag_name', |
|
|
|
|
|
category: 'meme', |
|
|
|
|
|
aliases: ['alias_shared', 'alias_new'], |
|
|
|
|
|
parent_tags: [parent_shared, parent_new], |
|
|
|
|
|
created_by_user: member, |
|
|
|
|
|
created_at: t_v2 |
|
|
|
|
|
) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
let!(:other_v1) do |
|
|
|
|
|
create_tag_version!( |
|
|
|
|
|
tag: other_tag, |
|
|
|
|
|
version_no: 1, |
|
|
|
|
|
event_type: 'create', |
|
|
|
|
|
name: 'other_tag_name', |
|
|
|
|
|
category: 'general', |
|
|
|
|
|
aliases: ['other_alias'], |
|
|
|
|
|
parent_tags: [other_parent], |
|
|
|
|
|
created_by_user: member, |
|
|
|
|
|
created_at: t_other |
|
|
|
|
|
) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
describe 'GET /tags/versions' do |
|
|
|
|
|
it 'returns all versions in reverse chronological order when id is omitted' do |
|
|
|
|
|
get '/tags/versions' |
|
|
|
|
|
|
|
|
|
|
|
expect(response).to have_http_status(:ok) |
|
|
|
|
|
expect(json).to include('versions', 'count') |
|
|
|
|
|
expect(json.fetch('count')).to eq(3) |
|
|
|
|
|
|
|
|
|
|
|
versions = json.fetch('versions') |
|
|
|
|
|
|
|
|
|
|
|
expect(versions.map { |v| [v['tag_id'], v['version_no']] }).to eq([ |
|
|
|
|
|
[other_tag.id, 1], |
|
|
|
|
|
[tag.id, 2], |
|
|
|
|
|
[tag.id, 1] |
|
|
|
|
|
]) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
it 'returns versions for the specified tag with diffs' do |
|
|
|
|
|
get '/tags/versions', params: { id: tag.id } |
|
|
|
|
|
|
|
|
|
|
|
expect(response).to have_http_status(:ok) |
|
|
|
|
|
expect(json).to include('versions', 'count') |
|
|
|
|
|
expect(json.fetch('count')).to eq(2) |
|
|
|
|
|
|
|
|
|
|
|
versions = json.fetch('versions') |
|
|
|
|
|
expect(versions.map { |v| v['tag_id'] }.uniq).to eq([tag.id]) |
|
|
|
|
|
expect(versions.map { |v| v['version_no'] }).to eq([2, 1]) |
|
|
|
|
|
|
|
|
|
|
|
latest = versions.first |
|
|
|
|
|
expect(latest).to include( |
|
|
|
|
|
'tag_id' => tag.id, |
|
|
|
|
|
'version_no' => 2, |
|
|
|
|
|
'event_type' => 'update', |
|
|
|
|
|
'created_by_user' => { |
|
|
|
|
|
'id' => member.id, |
|
|
|
|
|
'name' => member.name |
|
|
|
|
|
} |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
expect(latest.fetch('name')).to eq( |
|
|
|
|
|
'current' => 'new_tag_name', |
|
|
|
|
|
'prev' => 'old_tag_name' |
|
|
|
|
|
) |
|
|
|
|
|
expect(latest.fetch('category')).to eq( |
|
|
|
|
|
'current' => 'meme', |
|
|
|
|
|
'prev' => 'general' |
|
|
|
|
|
) |
|
|
|
|
|
expect(latest.fetch('aliases')).to include( |
|
|
|
|
|
{ 'name' => 'alias_shared', 'type' => 'context' }, |
|
|
|
|
|
{ 'name' => 'alias_new', 'type' => 'added' }, |
|
|
|
|
|
{ 'name' => 'alias_old', 'type' => 'removed' } |
|
|
|
|
|
) |
|
|
|
|
|
expect(latest.fetch('parent_tags')).to include( |
|
|
|
|
|
a_hash_including( |
|
|
|
|
|
'type' => 'context', |
|
|
|
|
|
'tag' => a_hash_including( |
|
|
|
|
|
'id' => parent_shared.id |
|
|
|
|
|
) |
|
|
|
|
|
), |
|
|
|
|
|
a_hash_including( |
|
|
|
|
|
'type' => 'added', |
|
|
|
|
|
'tag' => a_hash_including( |
|
|
|
|
|
'id' => parent_new.id |
|
|
|
|
|
) |
|
|
|
|
|
), |
|
|
|
|
|
a_hash_including( |
|
|
|
|
|
'type' => 'removed', |
|
|
|
|
|
'tag' => a_hash_including( |
|
|
|
|
|
'id' => parent_old.id |
|
|
|
|
|
) |
|
|
|
|
|
) |
|
|
|
|
|
) |
|
|
|
|
|
expect(latest.fetch('created_at')).to eq(t_v2.iso8601) |
|
|
|
|
|
|
|
|
|
|
|
first = versions.second |
|
|
|
|
|
expect(first).to include( |
|
|
|
|
|
'tag_id' => tag.id, |
|
|
|
|
|
'version_no' => 1, |
|
|
|
|
|
'event_type' => 'create', |
|
|
|
|
|
'created_by_user' => { |
|
|
|
|
|
'id' => member.id, |
|
|
|
|
|
'name' => member.name |
|
|
|
|
|
} |
|
|
|
|
|
) |
|
|
|
|
|
expect(first.fetch('name')).to eq( |
|
|
|
|
|
'current' => 'old_tag_name', |
|
|
|
|
|
'prev' => nil |
|
|
|
|
|
) |
|
|
|
|
|
expect(first.fetch('category')).to eq( |
|
|
|
|
|
'current' => 'general', |
|
|
|
|
|
'prev' => nil |
|
|
|
|
|
) |
|
|
|
|
|
expect(first.fetch('aliases')).to include( |
|
|
|
|
|
{ 'name' => 'alias_shared', 'type' => 'added' }, |
|
|
|
|
|
{ 'name' => 'alias_old', 'type' => 'added' } |
|
|
|
|
|
) |
|
|
|
|
|
expect(first.fetch('parent_tags')).to include( |
|
|
|
|
|
a_hash_including( |
|
|
|
|
|
'type' => 'added', |
|
|
|
|
|
'tag' => a_hash_including( |
|
|
|
|
|
'id' => parent_shared.id |
|
|
|
|
|
) |
|
|
|
|
|
), |
|
|
|
|
|
a_hash_including( |
|
|
|
|
|
'type' => 'added', |
|
|
|
|
|
'tag' => a_hash_including( |
|
|
|
|
|
'id' => parent_old.id |
|
|
|
|
|
) |
|
|
|
|
|
) |
|
|
|
|
|
) |
|
|
|
|
|
expect(first.fetch('created_at')).to eq(t_v1.iso8601) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
it 'returns empty when the specified tag has no versions' do |
|
|
|
|
|
fresh_tag = create(:tag, name: 'no_versions_tag', category: :general) |
|
|
|
|
|
|
|
|
|
|
|
get '/tags/versions', params: { id: fresh_tag.id } |
|
|
|
|
|
|
|
|
|
|
|
expect(response).to have_http_status(:ok) |
|
|
|
|
|
expect(json.fetch('versions')).to eq([]) |
|
|
|
|
|
expect(json.fetch('count')).to eq(0) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
it 'clamps page and limit to at least 1' do |
|
|
|
|
|
get '/tags/versions', params: { id: tag.id, page: 0, limit: 0 } |
|
|
|
|
|
|
|
|
|
|
|
expect(response).to have_http_status(:ok) |
|
|
|
|
|
expect(json.fetch('count')).to eq(2) |
|
|
|
|
|
|
|
|
|
|
|
versions = json.fetch('versions') |
|
|
|
|
|
expect(versions.size).to eq(1) |
|
|
|
|
|
expect(versions.first['version_no']).to eq(2) |
|
|
|
|
|
end |
|
|
|
|
|
end |
|
|
|
|
|
end |