Merge branch 'develop' into e2e

This commit is contained in:
Oleksii Kriuchykhin 2023-10-26 15:36:36 +02:00
commit 6235a03595
26 changed files with 231 additions and 86 deletions

View file

@ -1,6 +1,6 @@
env:
- DOCKER_COMPOSE_VERSION=1.23.2
- DOCKER_COMPOSE_VERSION=v2.22.0
dist: jammy
sudo: required
language: ruby
addons:
@ -10,9 +10,9 @@ services:
- docker
before_install:
- sudo rm /usr/local/bin/docker-compose
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64 > docker-compose
- chmod +x docker-compose
- sudo mv docker-compose /usr/local/bin
- make docker
- make docker-ci
script:
- make tests-ci

View file

@ -24,6 +24,9 @@ heroku:
docker:
@docker-compose build
docker-ci:
@docker-compose --progress plain build web
docker-production:
@docker-compose -f docker-compose.production.yml build --build-arg BUILD_TIMESTAMP=$(BUILD_TIMESTAMP)
@ -81,10 +84,17 @@ integration-tests:
@$(MAKE) rails cmd="bundle exec cucumber"
tests-ci:
@docker-compose run --rm web bash -c "bundle install && yarn install"
@docker-compose up -d webpack
@docker-compose ps
@docker-compose run -e ENABLE_EMAIL_CONFIRMATIONS=false -e MAIL_FROM=MAIL_FROM -e MAIL_REPLYTO=MAIL_REPLYTO -e RAILS_ENV=test -e MAIL_SERVER_URL=localhost:3000 -e ENABLE_RECAPTCHA=false -e ENABLE_USER_CONFIRMATION=false -e ENABLE_USER_REGISTRATION=true -e CORE_API_RATE_LIMIT=1000000 --rm web bash -c "rake db:create && rake db:migrate && yarn install && bundle exec rspec"
@docker-compose run --rm web bash -c "bundle install"
@docker-compose run -e ENABLE_EMAIL_CONFIRMATIONS=false \
-e MAIL_FROM=MAIL_FROM \
-e MAIL_REPLYTO=MAIL_REPLYTO \
-e RAILS_ENV=test \
-e MAIL_SERVER_URL=localhost:3000 \
-e ENABLE_RECAPTCHA=false \
-e ENABLE_USER_CONFIRMATION=false \
-e ENABLE_USER_REGISTRATION=true \
-e CORE_API_RATE_LIMIT=1000000 \
--rm web bash -c "rake db:create && rake db:migrate && bundle exec rspec ./spec/requests/api/"
console:
@$(MAKE) rails cmd="rails console"

View file

@ -1 +1 @@
1.29.0.1
1.29.1.1

View file

@ -430,7 +430,7 @@ var ProjectsIndex = (function() {
view_mode: $('.projects-index').data('view-mode'),
sort: projectsCurrentSort,
search: projectsViewSearch,
members: membersFilter,
members: membersFilter && membersFilter.map(m => m.value),
created_on_from: createdOnFromFilter,
created_on_to: createdOnToFilter,
folders_search: lookInsideFolders,
@ -549,6 +549,8 @@ var ProjectsIndex = (function() {
var datePicker = $field.data('DateTimePicker');
if (datePicker && datePicker.date()) {
return datePicker.date()._d.toUTCString();
} else if ($field.val()) {
return moment($field.val(), $field.data('dateFormat'))._d.toUTCString();
}
return null;
}
@ -565,8 +567,8 @@ var ProjectsIndex = (function() {
let $textFilter = $('#textSearchFilterInput', $projectsFilter);
function getFilterValues() {
createdOnFromFilter = selectDate($createdOnFromFilter) || $createdOnFromFilter.val();
createdOnToFilter = selectDate($createdOnToFilter) || $createdOnToFilter.val();
createdOnFromFilter = selectDate($createdOnFromFilter);
createdOnToFilter = selectDate($createdOnToFilter);
membersFilter = dropdownSelector.getData($('.members-filter'));
lookInsideFolders = $foldersCB.prop('checked') || '';
archivedOnFromFilter = selectDate($archivedOnFromFilter) || $archivedOnFromFilter.val();

View file

@ -20,7 +20,7 @@
width: 100%;
.dataTables_scrollHead {
overflow: visible !important;
flex-shrink: 0;
thead {
.sci-checkbox-container {

View file

@ -1,7 +1,7 @@
@layer components {
.sci-label {
@apply text-sm font-medium text-sn-grey;
@apply text-sm font-medium text-sn-dark-grey;
}
.sci-input-container-v2 {

View file

@ -12,7 +12,6 @@ module Api
timestamps_filter(
@inventory_column.repository_status_items
)
.repository_status_items
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))

View file

@ -137,14 +137,13 @@ module ApplicationHelper
# and outputs a popover with user information
def smart_annotation_filter_users(text, team, base64_encoded_imgs: false)
sa_user = /\[\@(.*?)~([0-9a-zA-Z]+)\]/
new_text = text.gsub(sa_user) do |el|
text.gsub(sa_user) do |el|
match = el.match(sa_user)
user = User.find_by_id(match[2].base62_decode)
next unless user
popover_for_user_name(user, team, false, false, base64_encoded_imgs)
end
sanitize_input(new_text)
end
# Generate smart annotation link for one user object

View file

@ -210,6 +210,14 @@
@publish="publishProtocol"
@cancel="closePublishModal"
/>
<clipboardPasteModal v-if="showClipboardPasteModal"
:image="pasteImages"
:objects="steps"
:objectType="'step'"
:selectedObjectId="firstObjectInViewport()"
@files="uploadFilesToStep"
@cancel="showClipboardPasteModal = false"
/>
</div>
</template>
@ -221,6 +229,8 @@
import Tinymce from '../shared/tinymce.vue'
import ReorderableItemsModal from '../shared/reorderable_items_modal.vue'
import PublishProtocol from './modals/publish_protocol.vue'
import clipboardPasteModal from '../shared/content/attachments/clipboard_paste_modal.vue'
import AssetPasteMixin from '../shared/content/attachments/mixins/paste.js'
import UtilsMixin from '../mixins/utils.js'
import stackableHeadersMixin from '../mixins/stackableHeadersMixin';
@ -234,8 +244,8 @@
required: true
}
},
components: { Step, InlineEdit, ProtocolOptions, Tinymce, ReorderableItemsModal, ProtocolMetadata, PublishProtocol},
mixins: [UtilsMixin, stackableHeadersMixin, moduleNameObserver],
components: { Step, InlineEdit, ProtocolOptions, Tinymce, ReorderableItemsModal, ProtocolMetadata, PublishProtocol, clipboardPasteModal},
mixins: [UtilsMixin, stackableHeadersMixin, moduleNameObserver, AssetPasteMixin],
computed: {
inRepository() {
return this.protocol.attributes.in_repository
@ -245,7 +255,7 @@
},
urls() {
return this.protocol.attributes.urls || {}
}
},
},
data() {
return {
@ -433,6 +443,16 @@
$('.my_module-name .view-mode').trigger('click');
$('.my_module-name .input-field').focus();
}, 300)
},
uploadFilesToStep(file, stepId) {
this.$children.find(child => child.step?.id == stepId).uploadFiles(file);
},
firstObjectInViewport() {
let step = $('.step-container:not(.locked)').toArray().find(element => {
const { top, bottom } = element.getBoundingClientRect()
return bottom > 0 && top < window.innerHeight
})
return step ? step.dataset.id : null
}
}
}

View file

@ -4,7 +4,8 @@
@drop.prevent="dropFile"
@dragenter.prevent="dragEnter($event)"
@dragover.prevent
:class="{ 'draging-file': dragingFile, 'editing-name': editingName }"
:data-id="step.id"
:class="{ 'draging-file': dragingFile, 'editing-name': editingName, 'locked': !urls.update_url }"
>
<div class="drop-message" @dragleave.prevent="!showFileModal ? dragingFile = false : null">
{{ i18n.t('protocols.steps.drop_message', { position: step.attributes.position + 1 }) }}
@ -134,12 +135,6 @@
</div>
</div>
<deleteStepModal v-if="confirmingDelete" @confirm="deleteStep" @cancel="closeDeleteModal"/>
<clipboardPasteModal v-if="showClipboardPasteModal"
:parent="step"
:image="pasteImages"
@files="uploadFiles"
@cancel="showClipboardPasteModal = false"
/>
<ReorderableItemsModal v-if="reordering"
:title="i18n.t('protocols.steps.modals.reorder_elements.title', { step_position: step.attributes.position + 1 })"
:items="reorderableElements"
@ -162,7 +157,6 @@
import Checklist from '../shared/content/checklist.vue'
import deleteStepModal from './modals/delete_step.vue'
import Attachments from '../shared/content/attachments.vue'
import clipboardPasteModal from '../shared/content/attachments/clipboard_paste_modal.vue'
import ReorderableItemsModal from '../shared/reorderable_items_modal.vue'
import MenuDropdown from '../shared/menu_dropdown.vue'
@ -202,7 +196,6 @@
attachmentsReady: false,
confirmingDelete: false,
showFileModal: false,
showClipboardPasteModal: false,
showCommentsSidebar: false,
dragingFile: false,
reordering: false,
@ -226,7 +219,6 @@
StepText,
Checklist,
deleteStepModal,
clipboardPasteModal,
Attachments,
StorageUsage,
ReorderableItemsModal,
@ -542,10 +534,6 @@
rect.right <= (window.innerWidth || $(window).width())
);
},
copyPasteImageModal(pasteImages) {
this.pasteImages = pasteImages;
this.showClipboardPasteModal = true;
},
insertElement(element) {
let position = element.attributes.position;
this.elements = this.elements.map( s => {

View file

@ -46,8 +46,10 @@ export default {
},
mounted() {
this.$nextTick(() => {
const textHeight = this.$refs.textRef.scrollHeight
this.expandable = textHeight > 60 // 60px
if (this.$refs.textRef) {
const textHeight = this.$refs.textRef.scrollHeight
this.expandable = textHeight > 60 // 60px
}
})
},
}

View file

@ -3,7 +3,8 @@
@drop.prevent="dropFile"
@dragenter.prevent="dragEnter($event)"
@dragover.prevent
:class="{ 'bg-sn-super-light-blue': dragingFile, 'bg-white': !dragingFile }"
:data-id="result.id"
:class="{ 'bg-sn-super-light-blue': dragingFile, 'bg-white': !dragingFile, 'locked': locked }"
>
<div class="text-xl items-center flex flex-col text-sn-blue h-full justify-center left-0 absolute top-0 w-full"
v-if="dragingFile"

View file

@ -32,6 +32,14 @@
@result:drag_enter="dragEnter"
/>
</div>
<clipboardPasteModal v-if="showClipboardPasteModal"
:image="pasteImages"
:objects="results"
:objectType="'result'"
:selectedObjectId="firstObjectInViewport()"
@files="uploadFilesToResult"
@cancel="showClipboardPasteModal = false"
/>
</div>
</template>
@ -43,10 +51,13 @@
import stackableHeadersMixin from '../mixins/stackableHeadersMixin';
import moduleNameObserver from '../mixins/moduleNameObserver';
import clipboardPasteModal from '../shared/content/attachments/clipboard_paste_modal.vue'
import AssetPasteMixin from '../shared/content/attachments/mixins/paste.js'
export default {
name: 'Results',
components: { ResultsToolbar, Result },
mixins: [stackableHeadersMixin, moduleNameObserver],
components: { ResultsToolbar, Result, clipboardPasteModal },
mixins: [stackableHeadersMixin, moduleNameObserver, AssetPasteMixin],
props: {
url: { type: String, required: true },
canCreate: { type: String, required: true },
@ -136,6 +147,16 @@
},
dragEnter(id) {
this.activeDragResult = id;
},
uploadFilesToResult(file, resultId) {
this.$children.find(child => child.result?.id == resultId).uploadFiles(file);
},
firstObjectInViewport() {
let result = $('.result-wrapper:not(.locked)').toArray().find(element => {
const { top, bottom } = element.getBoundingClientRect()
return bottom > 0 && top < window.innerHeight
})
return result ? result.dataset.id : null
}
}
}

View file

@ -12,29 +12,68 @@
<h4 class="modal-title">{{i18n.t('assets.from_clipboard.modal_title')}}</h4>
</div>
<div class="modal-body">
<p><strong>{{i18n.t('assets.from_clipboard.image_preview')}}</strong></p>
<canvas style="border:1px solid grey;max-width:400px;max-height:300px" id="clipboardPreview" />
<p><strong>{{i18n.t('assets.from_clipboard.file_name')}}</strong></p>
<div class="input-group">
<input id="clipboardImageName" type="text" class="form-control"
<label class="sci-label">{{i18n.t('assets.from_clipboard.image_preview')}}</label>
<div class="flex justify-center w-full">
<canvas class="max-h-80 max-w-lg rounded border border-solid border-sn-light-grey" ref="preview" />
</div>
<div class="w-full py-6">
<label class="sci-label">{{i18n.t(`assets.from_clipboard.select_${objectType}`)}}</label>
<SelectSearch
:value="target"
@change="setTarget"
:options="targets"
:isLoading="false"
:placeholder="
i18n.t(`protocols.steps.modals.move_element.${objectType}.search_placeholder`)
"
:searchPlaceholder="
i18n.t(`protocols.steps.modals.move_element.${objectType}.search_placeholder`)
"
/>
</div>
<label class="sci-label">{{i18n.t('assets.from_clipboard.file_name')}}</label>
<div class="sci-input-container-v2">
<input id="clipboardImageName" type="text" class="sci-input-field !pr-16" v-model="fileName"
:placeholder="i18n.t('assets.from_clipboard.file_name_placeholder')" aria-describedby="image-name">
<span class="input-group-addon" id="image-name"></span>
<span class="absolute right-2.5 text-sn-grey ">
.{{ extension }}
</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @click="cancel">{{i18n.t('general.cancel')}}</button>
<button type="button" class="btn btn-success" @click="uploadImage">{{i18n.t('assets.from_clipboard.add_image')}}</button>
<button type="button" class="btn btn-success" :disabled="!valid" @click="uploadImage">{{i18n.t('assets.from_clipboard.add_image')}}</button>
</div>
</div>
</div>
</div>
</template>
<script>
import SelectSearch from "../../select_search.vue";
export default {
name: 'clipboardPasteModal',
props: {
parent: Object,
image: DataTransferItem
objects: Array,
image: DataTransferItem,
objectType: String,
selectedObjectId: String
},
data () {
return {
target: null,
targets: [],
fileName: '',
extension: '',
}
},
components: {
SelectSearch
},
computed: {
valid() {
return this.target && this.fileName.length > 0;
}
},
mounted() {
$(this.$refs.modal).modal('show');
@ -42,15 +81,26 @@
$(this.$refs.modal).on('hidden.bs.modal', () => {
this.$emit('cancel');
});
if (this.selectedObjectId) this.target = this.selectedObjectId;
this.targets = this.objects.map((object) => {
return [
object.id,
object.attributes.name
]
});
},
methods: {
setTarget(target) {
this.target = target;
},
cancel() {
$(this.$refs.modal).modal('hide');
},
appendImage(item) {
let imageBlob = item.getAsFile();
if (imageBlob) {
var canvas = document.getElementById('clipboardPreview');
var canvas = this.$refs.preview;
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
@ -63,12 +113,12 @@
let extension = imageBlob.name.slice(
(Math.max(0, imageBlob.name.lastIndexOf('.')) || Infinity) + 1
);
$('#image-name').html('.' + extension); // add extension near file name
this.extension = extension;
this.imageBlob = imageBlob;
}
},
uploadImage() {
let newName = $('#clipboardImageName').val();
let newName = this.fileName;
let imageBlog = this.imageBlob;
// check if the name is set
if (newName && newName.length > 0) {
@ -82,7 +132,7 @@
this.imageBlob = new File([blob], name, { type: imageBlog.type });
}
$(this.$refs.modal).modal('hide');
this.$emit('files', this.imageBlob);
this.$emit('files', this.imageBlob, this.target);
}
}
}

View file

@ -0,0 +1,32 @@
export default {
data() {
return {
showClipboardPasteModal: false,
pasteImages: null,
};
},
mounted() {
document.addEventListener('paste', this.handlePaste);
},
unmounted() {
document.removeEventListener('paste', this.handlePaste);
},
methods: {
handlePaste(e) {
if ( e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' ) return;
this.pasteImages = this.getImagesFromClipboard(e);
if (this.pasteImages && this.firstObjectInViewport()) this.showClipboardPasteModal = true;
},
getImagesFromClipboard(e) {
let image = null;
if (e.clipboardData) {
for (let i = 0; i < e.clipboardData.items.length; i++) {
if (e.clipboardData.items[i].type.indexOf('image') !== -1) {
image = e.clipboardData.items[i];
}
}
}
return image;
},
},
};

View file

@ -18,8 +18,8 @@
data-placement="top"
data-toggle="popover"
data-content=""
data-full-name="<%= user.full_name %>"
data-email="<%= user.email %>"
data-full-name="<%= escape_input(user.full_name) %>"
data-email="<%= escape_input(user.email) %>"
data-popover-html="<%= popover_html %>"
data-user-avatar-popover-absolute-url="<%= user_avatar_absolute_url(
user,
@ -27,7 +27,7 @@
base64_encoded_imgs
) %>"
>
<%= user.full_name %>
<%= escape_input(user.full_name) %>
</a>
<% unless skip_user_status || user_still_in_team %>
<%= I18n.t('atwho.res.removed') %>

View file

@ -325,6 +325,7 @@ class Constants
config[:attributes][:all] << 'id'
config[:attributes][:all] << 'contenteditable'
config[:attributes]['img'] << 'data-mce-token'
config[:attributes]['img'] << 'data-source-type'
config[:protocols]['img']['src'] << 'data'
INPUT_SANITIZE_CONFIG = Sanitize::Config.freeze_config(config)

View file

@ -3454,9 +3454,11 @@ en:
drop_label: 'Drop to add to Step'
file_label: 'File'
from_clipboard:
modal_title: 'Add image from clipboard'
image_preview: 'Image preview'
add_image: 'Add'
modal_title: 'Insert image from clipboard'
image_preview: 'Pasted image preview'
select_step: 'Select to which step youd like to attach image'
select_result: 'Select to which result youd like to attach image'
add_image: 'Insert'
file_name: 'File name'
file_name_placeholder: 'Image'
placeholder:

View file

@ -7,6 +7,9 @@ FactoryBot.define do
description { Faker::Lorem.sentence }
space_taken { 1048576 }
without_templates { true }
after(:create) do |team|
team.created_by.update(current_team_id: team.id)
end
trait :with_members do
users { create_list :user, 3 }
end

View file

@ -44,7 +44,7 @@ RSpec.describe "Api::V1::ExperimentsController", type: :request do
it 'Response with correct experiments, only active' do
hash_body = nil
get api_v1_team_project_experiments_path(team_id: @teams.first.id,
get api_v1_team_project_experiments_path(team_id: @team1.id,
project_id: @valid_project, filter: { archived: false }), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data].pluck('attributes').pluck('archived').none?).to be(true)
@ -60,7 +60,7 @@ RSpec.describe "Api::V1::ExperimentsController", type: :request do
it 'Response with correct experiments, only archived' do
hash_body = nil
get api_v1_team_project_experiments_path(team_id: @teams.first.id,
get api_v1_team_project_experiments_path(team_id: @team1.id,
project_id: @valid_project, filter: { archived: true }), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data].pluck('attributes').pluck('archived').all?).to be(true)

View file

@ -6,14 +6,21 @@ RSpec.describe "Api::V1::ProjectUserAssignmentsController", type: :request do
before :all do
@user = create(:user)
@another_user = create(:user)
@first_project_owner_user = create(:user)
@team = create(:team, created_by: @user)
@normal_user_role = create :normal_user_role
create_user_assignment(@team, @normal_user_role, @another_user)
create_user_assignment(@team, @normal_user_role, @first_project_owner_user)
@own_project = create(:project, name: Faker::Name.unique.name, created_by: @user, team: @team)
@owner_role = UserRole.find_by(name: I18n.t('user_roles.predefined.owner'))
create_user_assignment(@own_project, @owner_role, @first_project_owner_user)
@invalid_project =
create(:project, name: Faker::Name.unique.name, created_by: @another_user, team: @team, visibility: :hidden)
@valid_headers = { 'Authorization': 'Bearer ' + generate_token(@user.id) }
@valid_headers = { Authorization: "Bearer #{generate_token(@user.id)}" }
@valid_headers_first_project_owner_user = {
Authorization: "Bearer #{generate_token(@first_project_owner_user.id)}"
}
end
describe 'GET #index' do
@ -29,15 +36,23 @@ RSpec.describe "Api::V1::ProjectUserAssignmentsController", type: :request do
)
end
it 'When invalid request, user in not an owner of the project' do
it 'When invalid request, user is not an owner of the team and do not have access to project' do
hash_body = nil
get api_v1_team_project_users_path(team_id: @team.id, project_id: @invalid_project.id),
headers: @valid_headers
headers: @valid_headers_first_project_owner_user
expect(response).to have_http_status(403)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 403)
end
it 'When invalid request, user is an owner of the team and do not have access to project' do
hash_body = nil
get api_v1_team_project_users_path(team_id: @team.id, project_id: @invalid_project.id),
headers: @valid_headers
expect(response).to have_http_status(200)
expect { hash_body = json }.not_to raise_exception
end
it 'When invalid request, non existing project' do
hash_body = nil
get api_v1_team_project_users_path(team_id: @team.id, project_id: -1), headers: @valid_headers
@ -66,9 +81,9 @@ RSpec.describe "Api::V1::ProjectUserAssignmentsController", type: :request do
get api_v1_team_project_user_path(
team_id: @team.id, project_id: @invalid_project.id, id: -1
), headers: @valid_headers
expect(response).to have_http_status(403)
expect(response).to have_http_status(404)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 403)
expect(hash_body['errors'][0]).to include('status': 404)
end
it 'When invalid request, non existing project' do
@ -161,7 +176,7 @@ RSpec.describe "Api::V1::ProjectUserAssignmentsController", type: :request do
project_id: @invalid_project.id
),
params: request_body.to_json,
headers: @valid_headers
headers: @valid_headers_first_project_owner_user
)
expect(response).to have_http_status(403)
@ -180,7 +195,7 @@ RSpec.describe "Api::V1::ProjectUserAssignmentsController", type: :request do
api_v1_team_project_user_path(
team_id: @own_project.team.id,
project_id: @own_project.id,
id: @own_project.user_assignments.first.id
id: @own_project.user_assignments.last.id
),
params: request_body.to_json,
headers: @valid_headers
@ -246,7 +261,7 @@ RSpec.describe "Api::V1::ProjectUserAssignmentsController", type: :request do
}
end
it 'renders 403' do
it 'renders 404' do
patch(
api_v1_team_project_user_path(
team_id: @invalid_project.team.id,
@ -257,7 +272,7 @@ RSpec.describe "Api::V1::ProjectUserAssignmentsController", type: :request do
headers: @valid_headers
)
expect(response).to have_http_status(403)
expect(response).to have_http_status(404)
end
end
end

View file

@ -14,7 +14,7 @@ RSpec.describe 'Api::V1::ProjectsController', type: :request do
project = create(:project, name: Faker::Name.unique.name, created_by: @user, team: @team1)
end
2.times do
project = create(:project, name: Faker::Name.unique.name, created_by: @user, team: @teams.first, archived: true)
project = create(:project, name: Faker::Name.unique.name, created_by: @user, team: @team1, archived: true)
end
# unaccessable_projects
@ -44,14 +44,14 @@ RSpec.describe 'Api::V1::ProjectsController', type: :request do
it 'Response with correct projects, only active' do
hash_body = nil
get api_v1_team_projects_path(team_id: @teams.first.id, filter: { archived: false }),
get api_v1_team_projects_path(team_id: @team1.id, filter: { archived: false }),
headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data].pluck('attributes').pluck('archived').none?).to be(true)
expect(hash_body[:data]).to match(
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@teams.first.projects.active, each_serializer: Api::V1::ProjectSerializer)
.new(@team1.projects.active, each_serializer: Api::V1::ProjectSerializer)
.to_json
)['data']
)
@ -59,14 +59,14 @@ RSpec.describe 'Api::V1::ProjectsController', type: :request do
it 'Response with correct projects, only archived' do
hash_body = nil
get api_v1_team_projects_path(team_id: @teams.first.id, filter: { archived: true }),
get api_v1_team_projects_path(team_id: @team1.id, filter: { archived: true }),
headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data].pluck('attributes').pluck('archived').all?).to be(true)
expect(hash_body[:data]).to match(
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@teams.first.projects.archived, each_serializer: Api::V1::ProjectSerializer)
.new(@team1.projects.archived, each_serializer: Api::V1::ProjectSerializer)
.to_json
)['data']
)

View file

@ -14,7 +14,7 @@ RSpec.describe 'Api::V1::ProtocolTemplateController', type: :request do
@protocol_published = create(:protocol, :in_repository_published_version, team: @team, added_by: @user, parent: @protocol_published_original, version_number: 2)
@protocol_published_draft = create(:protocol, :in_repository_draft, team: @team, added_by: @user,
parent: @protocol_published_original, version_number: 3, name: @protocol_published_original.name)
@protocol_draft_second_team = create(:protocol, :in_repository_draft, team: @team2, added_by: @another_user)
@valid_headers = { 'Authorization': 'Bearer ' + generate_token(@user.id) }

View file

@ -129,14 +129,14 @@ RSpec.describe 'Api::V1::ResultsController', type: :request do
attributes: {
text: 'Result text 1 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAA'\
'AACCAIAAAD91JpzAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAE0lE'\
'QVQIHWP8//8/AwMDExADAQAkBgMBOOSShwAAAABJRU5ErkJggg==" data-mce-token="a1">'
'QVQIHWP8//8/AwMDExADAQAkBgMBOOSShwAAAABJRU5ErkJggg==" data-mce-token="1">'
} },
{ type: 'tiny_mce_assets',
attributes: {
file_data: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAA'\
'AACCAIAAAD91JpzAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAE0lE'\
'QVQIHWP8//8/AwMDExADAQAkBgMBOOSShwAAAABJRU5ErkJggg==',
file_token: 'a1',
file_token: '1',
file_name: 'test.png'
} }
]
@ -198,7 +198,7 @@ RSpec.describe 'Api::V1::ResultsController', type: :request do
it 'Response correct with old TinyMCE images' do
hash_body = nil
@valid_tinymce_hash_body[:included][0][:attributes][:text] = 'Result text 1 [~tiny_mce_id:a1]'
@valid_tinymce_hash_body[:included][0][:attributes][:text] = 'Result text 1 [~tiny_mce_id:1]'
post api_v1_team_project_experiment_task_results_path(
team_id: @team1.id,
project_id: @valid_project,

View file

@ -63,7 +63,7 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
expect(response).to have_http_status 200
expect(JSON.parse(response.body)['data'].map { |item| item['id'] }).to(
eq([@my_module_repository_row.id.to_s])
eq([@repository_row.id.to_s])
)
end
end
@ -76,14 +76,14 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @my_module.id,
id: @my_module_repository_row.id
id: @repository_row.id
),
headers: @valid_headers
)
expect(response).to have_http_status 200
expect(JSON.parse(response.body)['data']['id']).to(
eq(@my_module_repository_row.id.to_s)
eq(@repository_row.id.to_s)
)
end
end
@ -112,7 +112,7 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @my_module.id,
id: @my_module_repository_row.id
id: @repository_row.id
),
params: request_body.to_json,
headers: @valid_headers)
@ -130,7 +130,7 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
hash_including(
data: hash_including(
type: 'inventory_items',
attributes: hash_including(stock_consumption: "100.0") )
attributes: hash_including(stock_consumption: '100.0'))
)
)
end
@ -143,7 +143,7 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @my_module.id,
id: @my_module_repository_row.id
id: @repository_row.id
),
params: request_body.to_json,
headers: @valid_headers)

View file

@ -52,7 +52,7 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
it 'Response with correct tasks, only active' do
hash_body = nil
get api_v1_team_project_experiment_tasks_path(
team_id: @teams.first.id,
team_id: @team1.id,
project_id: @valid_project,
experiment_id: @valid_experiment,
filter: { archived: false }
@ -71,7 +71,7 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
it 'Response with correct tasks, only archived' do
hash_body = nil
get api_v1_team_project_experiment_tasks_path(
team_id: @teams.first.id,
team_id: @team1.id,
project_id: @valid_project,
experiment_id: @valid_experiment,
filter: { archived: true }