Skip to content

Commit

Permalink
add specs
Browse files Browse the repository at this point in the history
  • Loading branch information
microstudi committed Jul 25, 2024
1 parent 61e7497 commit 092d408
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ module Decidim
module Admin
class ShareTokensController < Decidim::Admin::ApplicationController
include Decidim::ComponentPathHelper
helper_method :share_token, :share_tokens, :component
include Decidim::Admin::Filterable

helper_method :share_token, :component

def index
enforce_permission_to :read, :share_token
@share_tokens = filtered_collection
end

def new
Expand Down Expand Up @@ -75,14 +78,20 @@ def component
@component ||= current_participatory_space.components.find(params[:component_id])
end

def share_tokens
Decidim::ShareToken.where(
organization: current_organization
)
def base_query
collection
end

def collection
@collection ||= Decidim::ShareToken.where(organization: current_organization, token_for: component)
end

def filters
[]
end

def share_token
@share_token ||= share_tokens.find(params[:id])
@share_token ||= collection.find(params[:id])
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
<a class="button button__sm button__secondary" href="<%= new_component_share_token_path %>"><%= icon "add-line" %><%= t("index.new_share_token_button", scope: "decidim.admin.share_tokens") %></a>
</h2>
</div>
<% if share_tokens.any? %>
<% if @share_tokens.any? %>
<div class="table-scroll">
<table class="table-list">
<thead>
<tr>
<th><%= t("models.share_token.fields.token", scope: "decidim.admin") %></th>
<th><%= t("models.share_token.fields.expires_at", scope: "decidim.admin") %></th>
<th><%= t("models.share_token.fields.registered_only", scope: "decidim.admin") %></th>
<th><%= t("models.share_token.fields.times_used", scope: "decidim.admin") %></th>
<th><%= sort_link(query, :token, t("models.share_token.fields.token", scope: "decidim.admin"), default_order: :desc) %></th>
<th><%= sort_link(query, :expires_at, t("models.share_token.fields.expires_at", scope: "decidim.admin"), default_order: :desc) %></th>
<th><%= sort_link(query, :registered_only, t("models.share_token.fields.registered_only", scope: "decidim.admin"), default_order: :desc) %></th>
<th><%= sort_link(query, :times_used, t("models.share_token.fields.times_used", scope: "decidim.admin"), default_order: :desc) %></th>
<th><%= t("models.share_token.fields.actions", scope: "decidim.admin") %></th>
</tr>
</thead>
<tbody>
<% share_tokens.each do |share_token| %>
<% @share_tokens.each do |share_token| %>
<tr>
<td id="js-token-<%= share_token.id %>"><%= share_token.token %></td>
<td><%= share_token.expires_at.present? ? ("<span class=\"text-#{share_token.expired? ? "warning" : ""}\">#{l(share_token.expires_at, format: :decidim_short)}</span>".html_safe) : content_tag(:em, t(".never")) %></td>
Expand All @@ -39,4 +39,4 @@
<p><%= t ".empty" %></p>
<% end %>
</div>
<% %>
<%= decidim_paginate @share_tokens %>
4 changes: 2 additions & 2 deletions decidim-admin/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -961,10 +961,10 @@ en:
preview: Preview
create:
invalid: There was a problem generating the token.
success: Token generated successfully.
success: Token created successfully.
destroy:
error: There was a problem destroying the token.
success: Token destroyed successfully.
success: Token successfully destroyed.
edit:
title: 'Edit sharing tokens for component: %{component_name}'
update: Update
Expand Down
48 changes: 43 additions & 5 deletions decidim-admin/spec/forms/share_token_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,58 @@ module Decidim::Admin
expect(form).to be_invalid
expect(form.errors[:token]).to include("cannot be blank")
end

context "when automatic_token is set" do
let(:token) { "" }
let(:automatic_token) { true }

it "does not validate presence of token" do
expect(form).to be_valid
end
end
end

context "when expires_at is nil" do
let!(:expires_at) { nil }
let(:expires_at) { nil }

it "does not expires" do
expect(form).to be_valid
it "validates presence of expires_at" do
expect(form).to be_invalid
expect(form.errors[:expires_at]).to include("cannot be blank")
end

context "when no_expiration is set" do
let(:no_expiration) { true }

it "does not expires" do
expect(form).to be_valid
end
end
end

context "when token is custom" do
let(:token) { "abc 123 " }

it "returns the token in uppercase" do
form.token = "abc123"
expect(form.token).to eq("ABC123")
expect(form.token).to eq("ABC-123")
end

context "and has strange characters" do
let(:token) { "abc 123 !@#$%^&*()_+" }

it "returns the token in uppercase" do
expect(form).to be_invalid
expect(form.errors[:token]).to include("is invalid")
end
end
end

context "when token exists" do
let(:automatic_token) { false }
let!(:share_token) { create(:share_token, organization:, token_for: component, token:) }

it "validates uniqueness of token" do
expect(form).to be_invalid
expect(form.errors[:token]).to include("has already been taken")
end
end

Expand Down
4 changes: 2 additions & 2 deletions decidim-core/app/packs/src/decidim/clipboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ $(() => {
}

let $msgEl = $el;
if($msgEl.text() === "") {
if ($msgEl.text() === "") {
$msgEl = $input;
}
// Get the available text to clipboard.
Expand Down Expand Up @@ -116,7 +116,7 @@ $(() => {
}
} else {
$msg = $('<div aria-role="alert" aria-live="assertive" aria-atomic="true" class="sr-only"></div>');
$el.after($msg);
$msgEl.append($msg);
$el.data("clipboard-message-element", $msg);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,67 @@ def visit_share_component
end

context "when visiting the component configuration page" do
context "when there are no tokens" do
let(:last_token) { Decidim::ShareToken.last }
before do
visit_share_component
end

it "displays empty message" do
expect(page).to have_content "There are no active tokens"
end

it "can create a new token with default options" do
click_on "New token"

click_on "Create"

expect(page).to have_content("Token created successfully")
expect(page).to have_css("tbody tr", count: 1)
within "tbody tr:last-child td:first-child" do
expect(page).to have_content(last_token.token)
end
within "tbody tr:last-child td:nth-child(2)" do
expect(page).to have_content("Never")
end
within "tbody tr:last-child td:nth-child(3)" do
expect(page).to have_content("No")
end
end

it "can create a new token with custom options" do
click_on "New token"

find_by_id("share_token_automatic_token_false").click
find_by_id("share_token_no_expiration_false").click
find_by_id("share_token_registered_only_true").click
click_on "Create"
expect(page).to have_content("cannot be blank", count: 2)

fill_in "share_token_token", with: " custom token "
fill_in "share_token_expires_at", with: 1.day.from_now, visible: :all
click_on "Create"

expect(page).to have_content("Token created successfully")
expect(page).to have_css("tbody tr", count: 1)
within "tbody tr:last-child td:first-child" do
expect(page).to have_content("CUSTOM-TOKEN")
end
within "tbody tr:last-child td:nth-child(2)" do
expect(page).to have_content(1.day.from_now.strftime("%d/%m/%Y %H:%M"))
end
within "tbody tr:last-child td:nth-child(3)" do
expect(page).to have_content("Yes")
end
end
end

context "when there are tokens" do
let!(:share_tokens) { create_list(:share_token, 3, token_for: component, organization: component.organization, registered_only: true) }
let!(:share_token) { share_tokens.last }

before do
visit_share_component
end

it "displays all tokens" do
within ".share_tokens" do
expect(page).to have_css("tbody tr", count: 3)
Expand All @@ -50,53 +103,77 @@ def visit_share_component
end
end

it "has to edit a share token" do
it "can edit a share token" do
within "tbody tr:first-child td:nth-child(3)" do
expect(page).to have_content("Yes")
end
within ".share_tokens tbody tr:first-child" do
click_on "Edit"
end

expect(page).to have_content("Edit sharing tokens for component")
expect(page).to have_css("#share_token_no_expiration_true")
find_by_id("share_token_no_expiration_false").click
find_by_id("share_token_registered_only_false").click
click_on "Update"
expect(page).to have_content("cannot be blank", count: 1)

fill_in "share_token_expires_at", with: 1.day.from_now, visible: :all
click_on "Update"

expect(page).to have_content("Token updated successfully")
expect(page).to have_css("tbody tr", count: 3)
within "tbody tr:first-child td:nth-child(2)" do
expect(page).to have_content(1.day.from_now.strftime("%d/%m/%Y %H:%M"))
end
within "tbody tr:first-child td:nth-child(3)" do
expect(page).to have_content("No")
end
end

it "allows copying the share link from the share token" do
within ".share_tokens tbody tr:first-child" do
click_on "Copy link"
expect(page).to have_content("Copied!")
expect(page).to have_css("[data-clipboard-copy-label]")
expect(page).to have_css("[data-clipboard-copy-message]")
expect(page).to have_css("[data-clipboard-content]")
end

expect(page).to have_css("[data-clipboard-copy-label]")
expect(page).to have_css("[data-clipboard-copy-message]")
expect(page).to have_css("[data-clipboard-content]")
end

it "has a share link for each token" do
urls = share_tokens.map(&:url).map { |url| url.split("?").first }
urls = share_tokens.map(&:url)
within ".share_tokens tbody tr:first-child" do
share_window = window_opened_by { click_on "Preview" }

within_window share_window do
expect(urls).to include(page.current_path)
expect(urls).to include(page.current_url)
end
end
end

it "has a link to delete tokens" do
it "can delete tokens" do
within ".share_tokens tbody tr:first-child" do
accept_confirm { click_on "Delete" }
end

expect(page).to have_admin_callout("successfully")
expect(page).to have_admin_callout("Token successfully destroyed")
expect(page).to have_css("tbody tr", count: 2)
end
end

context "when there are no tokens" do
context "when there are many pages" do
let!(:share_tokens) { create_list(:share_token, 16, token_for: component, organization: component.organization) }

before do
visit_share_component
end

it "displays empty message" do
expect(page).to have_content "There are no active tokens"
it "displays pagination" do
expect(page).to have_css("tbody tr", count: 15)
within '[aria-label="Pagination"]' do
click_on "Next"
end
expect(page).to have_css("tbody tr", count: 1)
end
end
end
Expand Down
41 changes: 41 additions & 0 deletions decidim-core/spec/models/decidim/share_token_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ module Decidim

let(:attributes) do
{
token:,
token_for:,
user:,
organization:
}
end

let(:token) { "SOME-TOKEN" }
let(:user) { create(:user) }
let(:token_for) { create(:component) }
let(:organization) { token_for.organization }
Expand All @@ -42,9 +44,48 @@ module Decidim

it { is_expected.not_to be_valid }
end

context "when token is not present" do
# FactoryBot does not run the after_initializer block when building if token is defined
let(:share_token) { build(:share_token, token_for:, organization:) }

it { is_expected.to be_valid }

it "generates a token" do
expect(subject.token).to be_present
end
end

context "when token is already taken" do
let(:token) { "taken" }

before do
create(:share_token, token:, token_for:, organization:)
end

it { is_expected.not_to be_valid }
end

context "when token is already taken by another component" do
let(:token) { "taken" }

before do
create(:share_token, token:, organization:)
end

it { is_expected.to be_valid }
end

context "when token has strange characters" do
let(:token) { "bon cop de falç" }

it { is_expected.to be_invalid }
end
end

describe "defaults" do
let(:share_token) { build(:share_token, token_for:, organization:) }

it "generates an alphanumeric 64-character token string" do
expect(subject.token).to match(/^[a-zA-Z0-9]{64}$/)
end
Expand Down
Loading

0 comments on commit 092d408

Please sign in to comment.