require "minitest/autorun" require "planka_api" require_relative "../lib/backlog" module BacklogTestHelpers # A hand-rolled fake of the subset of Planka::Client's resource surface # BoardEnsurer/Cards touches: projects, boards, lists, labels, cards, # comments. In-memory only, no network. Returns the real planka-api 0.2.0 # typed records (Planka::Types::*) so these tests exercise the same # accessor shapes production code does. class FakePlankaClient attr_reader :projects, :boards, :lists, :labels, :cards, :comments def initialize(reject_colors: []) @next_id = 0 @projects_store = [] @boards_store = [] @lists_store = [] @labels_store = [] @cards_store = [] @card_labels_store = [] @comments_store = [] @projects = ProjectsResource.new(self) @boards = BoardsResource.new(self) @lists = ListsResource.new(self) @labels = LabelsResource.new(self, reject_colors: reject_colors) @cards = CardsResource.new(self) @comments = CommentsResource.new(self) end def next_id = (@next_id += 1).to_s attr_reader :projects_store, :boards_store, :lists_store, :labels_store, :cards_store, :card_labels_store, :comments_store # Project managers aren't part of Types::Project (they're their own # join record, Types::ProjectManager) — tracked here so tests can # assert on the visibility-fix quirk (BoardEnsurer#fix_visibility). def managers_for(project_id) @managers_store ||= {} @managers_store[project_id] ||= [] end def attach_label(card_id, label_id) record = Planka::Types::CardLabel.new( id: next_id, created_at: nil, updated_at: nil, card_id: card_id, label_id: label_id ) @card_labels_store << record record end class ProjectsResource def initialize(client) = @client = client def list = @client.projects_store.dup def create(attrs) project = Planka::Types::Project.new( id: @client.next_id, created_at: nil, updated_at: nil, name: attrs[:name], description: nil, background_type: nil, background_gradient: nil, is_hidden: nil, owner_project_manager_id: @client.next_id, background_image_id: nil, is_favorite: nil ) @client.projects_store << project project end def update(id, attrs) project = @client.projects_store.find { |p| p.id == id } idx = @client.projects_store.index(project) updated = project updated = updated.with(owner_project_manager_id: attrs[:ownerProjectManagerId]) if attrs.key?(:ownerProjectManagerId) @client.projects_store[idx] = updated updated end def add_manager(project_id, user_id) @client.managers_for(project_id) << user_id Planka::Types::ProjectManager.new(id: @client.next_id, created_at: nil, updated_at: nil, project_id: project_id, user_id: user_id) end end class BoardsResource def initialize(client) = @client = client def list(project_id) @client.boards_store.select { |b| b.project_id == project_id } end def create(project_id, attrs) board = Planka::Types::Board.new( id: @client.next_id, created_at: nil, updated_at: nil, position: attrs[:position], name: attrs[:name], default_view: nil, default_card_type: nil, limit_card_types_to_default_one: nil, always_display_card_creator: nil, display_card_ages: nil, expand_task_lists_by_default: nil, project_id: project_id, is_subscribed: nil ) @client.boards_store << board board end def update(id, attrs) board = @client.boards_store.find { |b| b.id == id } idx = @client.boards_store.index(board) updated = board updated = updated.with(name: attrs[:name]) if attrs.key?(:name) @client.boards_store[idx] = updated updated end def get(id) board = @client.boards_store.find { |b| b.id == id } Planka::Types::BoardDetail.new( board: board, lists: @client.lists.list(id), labels: @client.labels.list(id), cards: @client.cards.all_for_board(id), card_labels: @client.card_labels_store.dup, board_memberships: [] ) end end class ListsResource def initialize(client) = @client = client def list(board_id) @client.lists_store.select { |l| l.board_id == board_id } end def create(board_id, attrs) raise ArgumentError, "list create requires type" unless attrs[:type] list = Planka::Types::List.new( id: @client.next_id, created_at: nil, updated_at: nil, type: attrs[:type], position: attrs[:position], name: attrs[:name], color: nil, board_id: board_id ) @client.lists_store << list list end end class CardsResource def initialize(client) = @client = client def create(list_id, attrs) raise ArgumentError, "card create requires type" unless attrs[:type] list = @client.lists_store.find { |l| l.id == list_id } card = Planka::Types::Card.new( id: @client.next_id, created_at: nil, updated_at: nil, type: attrs[:type], position: attrs[:position], name: attrs[:name], description: attrs[:description], due_date: nil, is_due_completed: nil, stopwatch: nil, comments_total: nil, is_closed: nil, list_changed_at: nil, board_id: list.board_id, list_id: list_id, creator_user_id: nil, prev_list_id: nil, cover_attachment_id: nil, is_subscribed: nil ) @client.cards_store << card card end def all_for_board(board_id) @client.cards_store.select { |c| c.board_id == board_id } end def move(id, list_id:, position:, board_id: nil) card = @client.cards_store.find { |c| c.id == id } idx = @client.cards_store.index(card) updated = card.with(list_id: list_id, position: position) updated = updated.with(board_id: board_id) if board_id @client.cards_store[idx] = updated updated end end class LabelsResource def initialize(client, reject_colors: []) @client = client @reject_colors = reject_colors end def list(board_id) @client.labels_store.select { |l| l.board_id == board_id } end def create(board_id, attrs) if @reject_colors.include?(attrs[:color]) raise Planka::ValidationError.new(status: 422, body: { "message" => "color #{attrs[:color]} rejected" }) end label = Planka::Types::Label.new( id: @client.next_id, created_at: nil, updated_at: nil, position: attrs[:position], name: attrs[:name], color: attrs[:color], board_id: board_id ) @client.labels_store << label label end def attach_to_card(card_id, label_id) @client.attach_label(card_id, label_id) end end class CommentsResource def initialize(client) @client = client end def store = @client.comments_store def create(card_id, attrs) comment = Planka::Types::Comment.new( id: @client.next_id, created_at: nil, updated_at: nil, text: attrs[:text], card_id: card_id, user_id: nil ) @client.comments_store << comment comment end end end end