chore: init commit
in worker.../repo/GITFOLDER.zip is the .git folder.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class NavbarPolicyVisibilityTest < ActionDispatch::IntegrationTest
|
||||
include Devise::Test::IntegrationHelpers
|
||||
|
||||
def setup
|
||||
classroom = create(:classroom)
|
||||
@student = User.create!(username: "student", type: "Student", password: "password", classroom: classroom)
|
||||
@teacher = User.create!(username: "teacher", type: "Teacher", password: "password", email: "teacher@test.com")
|
||||
@admin = User.create!(
|
||||
username: "admin", type: "Teacher", admin: true, password: "password",
|
||||
email: "admin@test.com"
|
||||
)
|
||||
@portfolio = Portfolio.create!(user: @student)
|
||||
end
|
||||
|
||||
test "student sees My Portfolio if permitted" do
|
||||
sign_in @student
|
||||
get root_path
|
||||
assert_select "a", text: "My Portfolio"
|
||||
end
|
||||
|
||||
test "teacher sees Classes if permitted" do
|
||||
sign_in @teacher
|
||||
get root_path
|
||||
assert_select "a", text: "Classes"
|
||||
end
|
||||
|
||||
test "admin sees Admin if permitted" do
|
||||
sign_in @admin
|
||||
get root_path
|
||||
assert_select "a", text: "Admin"
|
||||
end
|
||||
|
||||
test "navbar shows only active stocks" do
|
||||
active_stock = create(:stock, archived: false, ticker: "AAPL")
|
||||
archived_stock = create(:stock, archived: true, ticker: "DEAD")
|
||||
|
||||
sign_in @student
|
||||
get root_path
|
||||
|
||||
assert_select "p", text: active_stock.ticker
|
||||
assert_select "p", text: archived_stock.ticker, count: 0
|
||||
end
|
||||
|
||||
test "navbar stocks are displayed in trading floor dropdown" do
|
||||
active_stock1 = create(:stock, archived: false, ticker: "AAPL")
|
||||
active_stock2 = create(:stock, archived: false, ticker: "GOOGL")
|
||||
archived_stock = create(:stock, archived: true, ticker: "DEAD")
|
||||
|
||||
sign_in @student
|
||||
get root_path
|
||||
|
||||
assert_select "details[data-controller='stock-navbar-toggle']" do
|
||||
assert_select "p", text: active_stock1.ticker
|
||||
assert_select "p", text: active_stock2.ticker
|
||||
end
|
||||
|
||||
assert_select "details[data-controller='stock-navbar-toggle']" do
|
||||
assert_select "p", text: archived_stock.ticker, count: 0
|
||||
end
|
||||
end
|
||||
|
||||
test "navbar stocks link to correct stock paths" do
|
||||
active_stock = create(:stock, archived: false, ticker: "AAPL")
|
||||
|
||||
sign_in @student
|
||||
get root_path
|
||||
|
||||
assert_select "a[href='#{stock_path(active_stock)}']" do
|
||||
assert_select "p", text: active_stock.ticker
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,169 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class OrderExecutionWorkflowTest < ActionDispatch::IntegrationTest
|
||||
test "buy order execution updates portfolio correctly" do
|
||||
classroom = create(:classroom, :with_trading)
|
||||
student = create(:student, classroom: classroom)
|
||||
portfolio = student.portfolio
|
||||
initial_deposit_cents = 100_000
|
||||
create(:portfolio_transaction, :deposit, portfolio: portfolio, amount_cents: initial_deposit_cents)
|
||||
|
||||
stock = create(:stock, ticker: "AAPL", price_cents: 15_000)
|
||||
shares_to_buy = 3
|
||||
order = create(:order, :pending, :buy, user: student, stock: stock, shares: shares_to_buy)
|
||||
purchase_cost_cents = stock.price_cents * shares_to_buy
|
||||
|
||||
# Sanity check: order is pending
|
||||
assert order.pending?, "order should be pending before job execution"
|
||||
|
||||
OrderExecutionJob.perform_now
|
||||
|
||||
order.reload
|
||||
portfolio.reload
|
||||
|
||||
assert order.completed?, "order should be marked as completed"
|
||||
assert_not_nil order.portfolio_transaction, "order should have linked transaction"
|
||||
assert_not_nil order.portfolio_stock, "order should have linked portfolio stock"
|
||||
|
||||
assert order.portfolio_transaction.debit?, "buy order should create debit transaction"
|
||||
assert_equal purchase_cost_cents, order.portfolio_transaction.amount_cents
|
||||
|
||||
assert_equal shares_to_buy, order.portfolio_stock.shares
|
||||
assert_equal stock.id, order.portfolio_stock.stock_id
|
||||
|
||||
# Verify cash balance (cash_balance returns dollars)
|
||||
expected_cash_cents = initial_deposit_cents - purchase_cost_cents - PortfolioTransaction::TRANSACTION_FEE_CENTS
|
||||
actual_cash_cents = (portfolio.cash_balance * 100).to_i
|
||||
assert_equal expected_cash_cents, actual_cash_cents
|
||||
end
|
||||
|
||||
test "sell order execution updates portfolio correctly" do
|
||||
classroom = create(:classroom, :with_trading)
|
||||
student = create(:student, classroom: classroom)
|
||||
portfolio = student.portfolio
|
||||
|
||||
stock = create(:stock, ticker: "GOOGL", price_cents: 20_000)
|
||||
shares_owned = 10
|
||||
shares_to_sell = 4
|
||||
create(
|
||||
:portfolio_stock, portfolio: portfolio, stock: stock, shares: shares_owned,
|
||||
purchase_price: stock.current_price
|
||||
)
|
||||
|
||||
order = create(:order, :pending, :sell, user: student, stock: stock, shares: shares_to_sell)
|
||||
sale_proceeds_cents = stock.price_cents * shares_to_sell
|
||||
|
||||
# Sanity check
|
||||
assert order.pending?, "order should be pending before job execution"
|
||||
|
||||
OrderExecutionJob.perform_now
|
||||
|
||||
order.reload
|
||||
portfolio.reload
|
||||
|
||||
assert order.completed?, "order should be marked as completed"
|
||||
assert order.portfolio_transaction.credit?, "sell order should create credit transaction"
|
||||
assert_equal sale_proceeds_cents, order.portfolio_transaction.amount_cents
|
||||
assert_equal(-shares_to_sell, order.portfolio_stock.shares, "sell order should create negative shares record")
|
||||
|
||||
remaining_shares = portfolio.shares_owned(stock.id).to_i
|
||||
assert_equal shares_owned - shares_to_sell, remaining_shares
|
||||
end
|
||||
|
||||
test "multiple orders in single job run with single fee per user" do
|
||||
classroom = create(:classroom, :with_trading)
|
||||
|
||||
student1 = create(:student, classroom: classroom)
|
||||
create(:portfolio_transaction, :deposit, portfolio: student1.portfolio, amount_cents: 200_000)
|
||||
|
||||
student2 = create(:student, classroom: classroom)
|
||||
create(:portfolio_transaction, :deposit, portfolio: student2.portfolio, amount_cents: 200_000)
|
||||
|
||||
stock = create(:stock, ticker: "AAPL", price_cents: 10_000)
|
||||
|
||||
order1_s1 = create(:order, :pending, :buy, user: student1, stock: stock, shares: 2)
|
||||
order2_s1 = create(:order, :pending, :buy, user: student1, stock: stock, shares: 1)
|
||||
order1_s2 = create(:order, :pending, :buy, user: student2, stock: stock, shares: 3)
|
||||
|
||||
# Sanity checks
|
||||
assert order1_s1.pending?
|
||||
assert order2_s1.pending?
|
||||
assert order1_s2.pending?
|
||||
assert_equal 0, student1.portfolio.portfolio_transactions.fees.count
|
||||
assert_equal 0, student2.portfolio.portfolio_transactions.fees.count
|
||||
|
||||
OrderExecutionJob.perform_now
|
||||
|
||||
[order1_s1, order2_s1, order1_s2].each do |order|
|
||||
order.reload
|
||||
assert order.completed?, "all orders should be completed"
|
||||
end
|
||||
|
||||
student1.portfolio.reload
|
||||
student2.portfolio.reload
|
||||
|
||||
# Each user should have exactly 1 fee transaction, regardless of order count
|
||||
assert_equal 1, student1.portfolio.portfolio_transactions.fees.count, "student1 should have exactly 1 fee"
|
||||
assert_equal 1, student2.portfolio.portfolio_transactions.fees.count, "student2 should have exactly 1 fee"
|
||||
assert_equal PortfolioTransaction::TRANSACTION_FEE_CENTS,
|
||||
student1.portfolio.portfolio_transactions.fees.sum(:amount_cents)
|
||||
|
||||
s1_purchase_cost_cents = stock.price_cents * 3 # 2 + 1 shares
|
||||
s1_expected_cash_cents = 200_000 - s1_purchase_cost_cents - PortfolioTransaction::TRANSACTION_FEE_CENTS
|
||||
s1_actual_cash_cents = (student1.portfolio.cash_balance * 100).to_i
|
||||
assert_equal s1_expected_cash_cents, s1_actual_cash_cents
|
||||
|
||||
s2_purchase_cost_cents = stock.price_cents * 3
|
||||
s2_expected_cash_cents = 200_000 - s2_purchase_cost_cents - PortfolioTransaction::TRANSACTION_FEE_CENTS
|
||||
s2_actual_cash_cents = (student2.portfolio.cash_balance * 100).to_i
|
||||
assert_equal s2_expected_cash_cents, s2_actual_cash_cents
|
||||
end
|
||||
|
||||
test "mixed buy and sell orders execute correctly" do
|
||||
classroom = create(:classroom, :with_trading)
|
||||
student = create(:student, classroom: classroom)
|
||||
portfolio = student.portfolio
|
||||
initial_deposit_cents = 100_000
|
||||
create(:portfolio_transaction, :deposit, portfolio: portfolio, amount_cents: initial_deposit_cents)
|
||||
|
||||
stock1 = create(:stock, ticker: "AAPL", price_cents: 10_000)
|
||||
stock2 = create(:stock, ticker: "GOOGL", price_cents: 20_000)
|
||||
|
||||
initial_stock2_shares = 5
|
||||
create(
|
||||
:portfolio_stock, portfolio: portfolio, stock: stock2, shares: initial_stock2_shares,
|
||||
purchase_price: stock2.current_price
|
||||
)
|
||||
|
||||
buy_shares = 2
|
||||
sell_shares = 3
|
||||
buy_order = create(:order, :pending, :buy, user: student, stock: stock1, shares: buy_shares)
|
||||
sell_order = create(:order, :pending, :sell, user: student, stock: stock2, shares: sell_shares)
|
||||
|
||||
# Sanity checks
|
||||
assert buy_order.pending?
|
||||
assert sell_order.pending?
|
||||
|
||||
buy_cost_cents = stock1.price_cents * buy_shares
|
||||
sell_proceeds_cents = stock2.price_cents * sell_shares
|
||||
|
||||
OrderExecutionJob.perform_now
|
||||
|
||||
buy_order.reload
|
||||
sell_order.reload
|
||||
portfolio.reload
|
||||
|
||||
assert buy_order.completed?, "buy order should be completed"
|
||||
assert sell_order.completed?, "sell order should be completed"
|
||||
|
||||
assert_equal buy_shares, portfolio.shares_owned(stock1.id).to_i
|
||||
assert_equal initial_stock2_shares - sell_shares, portfolio.shares_owned(stock2.id).to_i
|
||||
|
||||
# Cash = initial + sell proceeds - buy cost - fee
|
||||
expected_cash_cents = initial_deposit_cents + sell_proceeds_cents - buy_cost_cents - PortfolioTransaction::TRANSACTION_FEE_CENTS
|
||||
actual_cash_cents = (portfolio.cash_balance * 100).to_i
|
||||
assert_equal expected_cash_cents, actual_cash_cents
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,91 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class OrdersScopingTest < ActionDispatch::IntegrationTest
|
||||
test "student sees only their own orders" do
|
||||
stock = create(:stock, price_cents: 1_000)
|
||||
classroom = create(:classroom, :with_trading)
|
||||
student1, order1 = create_student_and_order(stock, classroom)
|
||||
_student2, order2 = create_student_and_order(stock, classroom)
|
||||
sign_in(student1)
|
||||
|
||||
get orders_path
|
||||
|
||||
assert_response :success
|
||||
assert_select "tr##{dom_id(order1)}"
|
||||
assert_select "tr##{dom_id(order2)}", count: 0
|
||||
end
|
||||
|
||||
test "teacher sees orders from students in their classrooms" do
|
||||
stock = create(:stock, price_cents: 1_000)
|
||||
classroom1, order1 = create_classroom_and_student_order(stock)
|
||||
_classroom2, order2 = create_classroom_and_student_order(stock)
|
||||
classroom3, order3 = create_classroom_and_student_order(stock)
|
||||
teacher = create(:teacher, classrooms: [classroom1, classroom3])
|
||||
sign_in(teacher)
|
||||
|
||||
get orders_path
|
||||
|
||||
assert_response :success
|
||||
assert_select "tr##{dom_id(order1)}"
|
||||
assert_select "tr##{dom_id(order3)}"
|
||||
assert_select "tr##{dom_id(order2)}", count: 0
|
||||
end
|
||||
|
||||
test "admin sees all orders" do
|
||||
admin = create(:admin)
|
||||
stock = create(:stock, price_cents: 1_000)
|
||||
_classroom1, order1 = create_classroom_and_student_order(stock)
|
||||
_classroom2, order2 = create_classroom_and_student_order(stock)
|
||||
sign_in(admin)
|
||||
|
||||
get orders_path
|
||||
|
||||
assert_response :success
|
||||
assert_select "tr##{dom_id(order1)}"
|
||||
assert_select "tr##{dom_id(order2)}"
|
||||
end
|
||||
|
||||
test "user with no orders sees empty list" do
|
||||
stock = create(:stock, price_cents: 1_000)
|
||||
create_classroom_and_student_order(stock)
|
||||
student = create(:student)
|
||||
sign_in(student)
|
||||
|
||||
get orders_path
|
||||
|
||||
assert_response :success
|
||||
assert_select "tr[data-testid='no-orders']"
|
||||
end
|
||||
|
||||
test "teacher with no classrooms sees no orders" do
|
||||
stock = create(:stock, price_cents: 1_000)
|
||||
create_classroom_and_student_order(stock)
|
||||
teacher = create(:teacher, classrooms: [])
|
||||
sign_in(teacher)
|
||||
|
||||
get orders_path
|
||||
|
||||
assert_response :success
|
||||
assert_select "tr[data-testid='no-orders']"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_classroom_and_student_order(stock)
|
||||
classroom = create(:classroom, :with_trading)
|
||||
_student, order = create_student_and_order(stock, classroom)
|
||||
|
||||
[classroom, order]
|
||||
end
|
||||
|
||||
def create_student_and_order(stock, classroom)
|
||||
student = create(:student, classroom:)
|
||||
portfolio = create(:portfolio, user: student)
|
||||
create(:portfolio_transaction, :deposit, portfolio:, amount_cents: 10_000)
|
||||
order = create(:order, :buy, user: student, stock:)
|
||||
|
||||
[student, order]
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user