chore: init commit

in worker.../repo/GITFOLDER.zip is the .git folder.
This commit is contained in:
2026-08-11 14:44:09 -04:00
parent 0012380fd3
commit 392781f7aa
781 changed files with 65944 additions and 0 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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