class Constants(BaseConstants): name_in_url = 'BaseExperiment' players_per_group = 2 num_rounds = 1 BasePay = Currency(5) BasePrice = Currency(1) # SellingPrice = Currency(1) EmployeeRatio = 0.5 ManagerRatio = 0.25
class Constants(BaseConstants): players_per_group = 3 num_rounds = 3 name_in_url = 'guess_two_thirds' jackpot = Currency(100) guess_max = 100 instructions_template = 'guess_two_thirds/instructions.html'
class Constants(BaseConstants): players_per_group = None num_rounds = 10 name_in_url = 'beauty_contest' jackpot = Currency(10) guess_max = 100 instructions_template = 'beauty_contest/Instructions.html'
def configure_player(self, player): p = player.id_in_group duration_min = self.session.config[f"P{p}_duration_min"] duration_max = self.session.config[f"P{p}_duration_max"] player.duration = random.randint(duration_min, duration_max) price_min = self.session.config[f"P{p}_price_min"] price_max = self.session.config[f"P{p}_price_max"] player.price = Currency(random.randint(price_min, price_max))
def test_payoff(self): session = otree.session.create_session( session_config_name='two_rounds_1p', num_participants=1, ) # need to activate cache after creating a session # because inside create_session, cache is deactivated with otree.db.idmap.use_cache(): # for some reason id=1 test fails, because the session only has # participant with id=2. ah, that makes sense. even if the DB # is truncated, PKs will still be incremented, i think. participant = session.participant_set.first() round_players = participant.get_players() round_payoff = Currency(13) round_players[0].payoff = round_payoff round_players[1].payoff = round_payoff payoff = participant.payoff self.assertEqual(payoff, 2 * round_payoff) participation_fee = session.config['participation_fee'] self.assertEqual(participation_fee, 1.25) real_world_currency_per_point = session.config[ 'real_world_currency_per_point'] self.assertEqual(real_world_currency_per_point, 0.5) payoff_in_real_world_currency = payoff * real_world_currency_per_point payoff_plus_participation_fee = participant.payoff_plus_participation_fee( ) self.assertEqual(payoff_plus_participation_fee, payoff_in_real_world_currency + participation_fee) payments_url = reverse('SessionPayments', args=[session.code]) client = django.test.Client() resp = client.get(payments_url) html = resp.content.decode('utf-8') for amount in [ '\u20ac1.25', # participation fee '\u20ac13.00', # participant.payoff '\u20ac14.25' # base plus participant.payoff ]: self.assertIn(amount, html)
def helper(self): session = otree.session.create_session( session_config_name='two_rounds_1p', num_participants=1, ) # need to activate cache after creating a session # because inside create_session, cache is deactivated otree.db.idmap.activate_cache() participant = session.participant_set.get(id=1) round_players = participant.get_players() round_payoff = Currency(13) round_players[0].payoff = round_payoff round_players[1].payoff = round_payoff otree.db.idmap.deactivate_cache() payoff = participant.payoff self.assertEqual(payoff, 2 * round_payoff) participation_fee = session.config['participation_fee'] self.assertEqual(participation_fee, 1.25) real_world_currency_per_point = session.config[ 'real_world_currency_per_point'] self.assertEqual(real_world_currency_per_point, 0.5) payoff_in_real_world_currency = payoff * real_world_currency_per_point payoff_plus_participation_fee = participant.payoff_plus_participation_fee( ) self.assertEqual(payoff_plus_participation_fee, payoff_in_real_world_currency + participation_fee) payments_url = reverse('SessionPayments', args=[session.code]) client = django.test.Client() resp = client.get(payments_url) html = resp.content.decode('utf-8') for amount in [ '\u20ac1.25', # participation fee '\u20ac13.00', # participant.payoff '\u20ac14.25' # base plus participant.payoff ]: self.assertIn(amount, html)
def test_participant_payoff(self): '''Should be able to set participant.payoff directly''' session = otree.session.create_session( session_config_name='two_rounds_1p', num_participants=1, ) payoff = Currency(10) participant = session.participant_set.first() participant.payoff = payoff participant.save() participant = session.participant_set.first() self.assertEqual(participant.payoff, payoff)
def test_valid_but_invalid_error_message(self): '''valid individual fields but passes error_message''' values = dict(default_submission) values['f_char'] = Constants.invalid_f_char self.timeout_submit_form(values) auto_submit_defaults = { 'f_bool': False, 'f_char': '', 'f_currency': Currency(0), 'f_float': 0, 'f_posint': 0, } self.assert_player_fields(auto_submit_defaults)
class Constants(BaseConstants): # oTree Constants name_in_url = 'bret' players_per_group = None # ---------------------------------------------------------------------------------------------------------------- # # --- Overall Settings and Appearance --- # # ---------------------------------------------------------------------------------------------------------------- # # value of single collected box # if the bomb is not collected, player's payoff per round is determined by <box_value> times <boxes_collected> # note that the currency of any earnings is determined by the oTree settings in settings.py # if you set this to a decimal number, you must set POINTS_DECIMAL_PLACES in settings.py box_value = Currency(5) # number of rows and columns # i.e. the total number of boxes is determined by <num_rows> times <num_cols> num_rows = 5 num_cols = 5 # box height and box width in pixels # make sure that the size of the boxes fits the screen of the device # note that the layout is responsive, i.e. boxes will break into new rows if they don't fit box_height = '50px' box_width = '50px' # number of rounds to be played num_rounds = 2 # determines whether all rounds played are payed-off or whether one round is randomly chosen for payment # if <random_payoff = True>, one round is randomly determined for payment # if <random_payoff = False>, the final payoff of the task is the sum of all rounds played # note that this is only of interest for the case of <num_rounds> larger than 1 random_payoff = True # if <instructions = True>, a separate template "Instructions.html" is rendered prior to the task in round 1 # if <instructions = False>, the task starts immediately (e.g. in case of printed instructions) instructions = True # show feedback by resolving boxes, i.e. toggle boxes and show whether bomb was collected or not # if <feedback = True>, the button "Solve" will be rendered and active after game play ends ("Stop") # if <feedback = False>, the button "Solve" won't be rendered such that no feedback about game outcome is provided feedback = True # show results page summarizing the game outcome # if <results = True>, a separate page containing all relevant information is displayed after finishing the task # if <num_rounds> larger than 1, results are summarized in a table and only shown after all rounds have been played results = True # ---------------------------------------------------------------------------------------------------------------- # # --- Settings Determining Game Play --- # # ---------------------------------------------------------------------------------------------------------------- # # "dynamic" or "static" game play # if <dynamic = True>, one box per time interval is collected automatically # in case of <dynamic = True>, game play is affected by the variables <time_interval> and <random> below # if <dynamic = False>, subjects collect as many boxes as they want by clicking or entering the respective number # in case of <dynamic = False>, game play is affected by the variables <random>, <devils_game> and <undoable> dynamic = False # time interval between single boxes being collected (in seconds) # note that this only affects game play if <dynamic = True> time_interval = 1.00 # collect boxes randomly or systematically # if <random = False>, boxes are collected row-wise one-by-one, starting in the top-left corner # if <random = True>, boxes are collected randomly (Fisher-Yates Algorithm) # note that this affects game play in both cases, <dynamic = True> and <dynamic = False> random = True # determines whether static game play allows for selecting boxes by clicking or by entering a number # if <devils_game = True>, game play is similar to Slovic (1965), i.e. boxes are collected by subjects # if <devils_game = False>, subjects enter the number of boxes they want to collect # note that this only affects game play if <dynamic = False> devils_game = True # determine whether boxes can be toggled only once or as often as clicked # if <undoable = True> boxes can be selected and de-selected indefinitely often # if <undoable = False> boxes can be selected only once (i.e. decisions can not be undone) # note that this only affects game play if <dynamic = False> and <devils_game = True> undoable = True
from tests.timeout_submission.models import Player, Constants from tests.timeout_submission import views import django.test from otree.api import Submission, Currency, Page import itertools import time import otree.timeout.tasks #.submit_expired_url.schedule( from unittest.mock import patch, MagicMock test_client = django.test.Client() # tuple instead of dict so we don't mutate it by mistake default_submission = ( ('f_bool', True), ('f_char', 'hello'), ('f_currency', Currency(2)), ('f_float', 0.1), ('f_posint', 3), ) class PageWithTimeout(Page): timeout_seconds = 50 class PageWithNoTimeout(Page): pass class TestTimeout(TestCase):
class Player(BasePlayer): player_field = models.CurrencyField(initial=Currency(3.14)) align_group = models.CharField() align_participant = models.CharField()