Best Python code snippet using playwright-python
app.py
Source:app.py  
1# -* -coding: utf-8 -*-2from ..log import app_log, error_log, auth_log, log_with_user3from pyramid.authentication import SessionAuthenticationPolicy4from pyramid.authorization import ACLAuthorizationPolicy5from pyramid.events import NewRequest6from pyramid.security import NO_PERMISSION_REQUIRED7import hashlib8import json9import mimetypes10import pkg_resources11import pyramid.config12import pyramid.events13import pyramid.httpexceptions14import pyramid.i18n15import pyramid.settings16import pyramid.threadlocal17import pyramid.view18import risclog.sqlalchemy.serializer19import signal20import sw.allotmentclub21import sw.allotmentclub.application22import sw.allotmentclub.browser23import sw.allotmentclub.browser.auth24import sw.allotmentclub.browser.base25import sw.allotmentclub.version26import time27import traceback28import zope.component29import sentry_sdk30from sentry_sdk.integrations.pyramid import PyramidIntegration31from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration32def json_serializer(value, default, **kw):33    return json.dumps(value, default=default, **kw)34def check_csrf(request):35    token = request.session.get_csrf_token()36    csrf_token = request.POST.get('csrf_token')37    return token == str(csrf_token)38class WSGIWrapper(object):39    def __init__(self, app, **settings):40        self.app = app41        self.settings = settings42    def __call__(self, environ, start_response):43        def start_response_wrapper(status, headers, exc_info=None):44            self.mangle_headers(headers)45            return start_response(status, headers, exc_info)46        return self.app(environ, start_response_wrapper)47class DenyFrame(WSGIWrapper):48    def mangle_headers(self, headers):49        headers.append(('X-Frame-Options', 'SAMEORIGIN'))50class NoCache(WSGIWrapper):51    def mangle_headers(self, headers):52        headers.append(('cache-control', 'no-cache'))53        headers.append(('cache-control', 'no-store'))54        headers.append(('pragma', 'no-cache'))55class Portal(sw.allotmentclub.application.Application):56    """The portal application."""57    def __call__(self, global_config, **settings):58        super(Portal, self).__call__(**settings)59        app = self.make_wsgi_app(global_config)60        return app61    def configure(self):62        super(Portal, self).configure()63        self.configure_zca()64        mimetypes.add_type('application/font-woff', '.woff')65        mimetypes.add_type('application/x-font-ttf', '.ttf')66        registry = pyramid.registry.Registry(67            bases=(zope.component.getGlobalSiteManager(),))68        if self.settings.get('sentry.dsn', None):69            version = sw.allotmentclub.version.__version__70            sentry_sdk.init(71                release=f"sw-allotmentclub-backend@{version}",72                dsn=self.settings['sentry.dsn'],73                integrations=[PyramidIntegration(), SqlalchemyIntegration()])74        self.config = config = pyramid.config.Configurator(75            settings=self.settings,76            registry=registry)77        config.setup_registry(settings=self.settings)78        config.include('pyramid_beaker')79        config.include('pyramid_exclog')80        config.include('pyramid_tm')81        if self.testing:82            config.include('pyramid_mailer.testing')83        elif config.registry.settings.get('mail.enable') == 'false':84            config.include('sw.allotmentclub.printmailer')85        else:86            config.include('sw.allotmentclub.logmailer')87        # self.add_csrf_check()88        config.add_renderer(89            'json', risclog.sqlalchemy.serializer.json_renderer_factory(90                serializer=json_serializer))91        config.set_default_permission('view')92        config.set_authentication_policy(SessionAuthenticationPolicy())93        config.set_authorization_policy(ACLAuthorizationPolicy())94        config.set_root_factory(95            sw.allotmentclub.browser.auth.get_default_context)96        config.add_request_method(97            sw.allotmentclub.browser.auth.get_user, 'user', property=True)98        self.add_routes()99        config.scan(package=sw.allotmentclub.browser,100                    ignore=sw.allotmentclub.SCAN_IGNORE_TESTS)101    def configure_zca(self):102        pass103    def add_csrf_check(self):104        def check_request_for_csrf(event):105            request = event.request106            if request.POST and not check_csrf(request):107                # disable csrf check for login108                if request.path == '/login':109                    return110                raise sw.allotmentclub.browser.interfaces.CSRFForbidden()111        self.config.add_subscriber(check_request_for_csrf, NewRequest)112    def add_routes(self):113        config = self.config114        config.add_route('sentry_frontend', '/sentry_frontend')115        config.add_route('login', '/login')116        config.add_route('logout', '/logout')117        config.add_route('navigation', '/navigation')118        config.add_route('home', '/')119        config.add_route('map', '/map')120        config.add_route('infobrief_print', '/infobrief_print')121        config.add_route('calendar', '/calendar')122        config.add_route('calendar_event_add', '/calendar/add')123        config.add_route(124            'calendar_event_delete',125            '/calendar/{id}/delete',126            factory='..model.Event.context_factory'127        )128        config.add_route('map_download', '/map/download')129        config.add_route('parcel_list', '/parcels')130        config.add_route('parcel_map_upload', '/parcels/{id}/upload_map',131                         factory='..model.Parcel.context_factory')132        config.add_route('parcel_map_download_check',133                         '/parcels/{id}/check_download_map',134                         factory='..model.Parcel.context_factory')135        config.add_route('parcel_map_download', '/parcels/{id}/download_map',136                         factory='..model.Parcel.context_factory')137        config.add_route('depot', '/depot')138        config.add_route('mail_add', '/mail/add')139        config.add_route('mail_list_inbox', '/mail/inbox')140        config.add_route('mail_list_sent', '/mail/sent')141        config.add_route('mail_list_drafts', '/mail/drafts')142        config.add_route('mail_edit', '/mail/{id}/edit',143                         factory='..mail.Message.context_factory')144        config.add_route('mail_reply', '/mail/{id}/reply',145                         factory='..mail.Message.context_factory')146        config.add_route('mail_status', '/mail/{id}/status',147                         factory='..mail.Message.context_factory')148        config.add_route('mail_preview', '/mail/{id}/preview',149                         factory='..mail.Message.context_factory')150        config.add_route('mail_print', '/mail/{id}/download',151                         factory='..mail.Message.context_factory')152        config.add_route('mail_send', '/mail/{id}/send',153                         factory='..mail.Message.context_factory')154        config.add_route('mail_duplicate', '/mail/{id}/duplicate',155                         factory='..mail.Message.context_factory')156        config.add_route('mail_delete', '/mail/{id}/delete',157                         factory='..mail.Message.context_factory')158        config.add_route('mail_list_attachments', '/mail/{id}/attachments',159                         factory='..mail.Message.context_factory')160        config.add_route('mail_attachment_del', '/mail/attachment/{id}/del',161                         factory='..mail.Attachment.context_factory')162        config.add_route('mail_attachment_white_page',163                         '/mail/attachment/{id}/change_white_page',164                         factory='..mail.Attachment.context_factory')165        config.add_route('mail_attachment_download',166                         '/mail/attachment/{id}/download',167                         factory='..mail.Attachment.context_factory')168        config.add_route('mail_postmark_open_tracking_webhook',169                         '/mail/postmark_open_tracking_webhook')170        config.add_route('mail_postmark_inbound_webhook',171                         '/mail/postmark_inbound_webhook')172        config.add_route('member_assignments', '/members/assignment_attendees')173        config.add_route('member_assignments_bill',174                         '/members/assignment_attendees/bill')175        config.add_route('member_assignments_detail',176                         '/members/assignment_attendees/{id}/list',177                         factory='..model.Member.context_factory')178        config.add_route('member_add', '/members/add')179        config.add_route('member_edit',180                         '/members/{id}/edit',181                         factory='..model.Member.context_factory')182        config.add_route('member_attachment_add',183                         '/members/{id}/attachments/add',184                         factory='..model.Member.context_factory')185        config.add_route('member_attachment', '/members/{id}/attachments',186                         factory='..model.Member.context_factory')187        config.add_route(188            'member_attachment_download',189            '/members/{member_id}/attachments/{id}/download',190            factory='..model.MemberAttachment.context_factory')191        config.add_route(192            'member_attachment_delete',193            '/members/{member_id}/attachments/{id}/delete',194            factory='..model.MemberAttachment.context_factory')195        config.add_route('member_account_list', '/members/account_list')196        config.add_route('member_account_detail_list',197                         '/members/{id}/account_details',198                         factory='..model.Member.context_factory')199        config.add_route(200            'member_account_detail_switch_ir',201            '/members/{member_id}/account_details/{id}/switch',202            factory='.account.AccountDetailFactory')203        config.add_route('banking_account_list', '/accounts/list')204        config.add_route('banking_account_list_detail',205                         '/accounts/{id}/detail',206                         factory='..account.BookingKind.context_factory')207        config.add_route('banking_account_list_report', '/accounts/report.pdf')208        config.add_route('sepa_sammler_list', '/accounts/sepa_sammler')209        config.add_route('sepa_sammler_add', '/accounts/sepa_sammler/add')210        config.add_route(211            'sepa_ueberweisung_add',212            '/accounts/sepa_sammler/add_ueberweisung'213        )214        config.add_route('sepa_sammler_edit',215                         '/accounts/sepa_sammler/{id}/edit',216                         factory='..account.SEPASammler.context_factory')217        config.add_route('sepa_sammler_export',218                         '/accounts/sepa_sammler/{id}/export',219                         factory='..account.SEPASammler.context_factory')220        config.add_route('sepa_sammler_update',221                         '/accounts/sepa_sammler/{id}/update',222                         factory='..account.SEPASammler.context_factory')223        config.add_route('sepa_sammler_entry_list',224                         '/accounts/sepa_sammler/{id}/entries',225                         factory='..account.SEPASammler.context_factory')226        config.add_route('sepa_direct_debit', '/accounts/sepa_direct_debit')227        config.add_route('booking_list', '/accounts/{id}/list',228                         factory='..account.BankingAccount.context_factory')229        config.add_route('split_booking', '/booking/{id}/split',230                         factory='..account.Booking.context_factory')231        config.add_route('map_booking', '/booking/{id}/map',232                         factory='..account.Booking.context_factory')233        config.add_route('waste_water', '/waste_water')234        config.add_route('property_tax_b', '/property_tax_b')235        config.add_route('member_list', '/members')236        config.add_route('member_list_leased', '/members_leased')237        config.add_route('member_list_passive', '/members_passive')238        config.add_route('member_list_tap_water', '/members_tap_water')239        config.add_route('member_sale_history', '/members/sale_history')240        config.add_route('membership_fee', '/members/insert_membership_fee')241        config.add_route('member_sale',242                         '/members/{id}/sale',243                         factory='..model.Member.context_factory')244        config.add_route('direct_debit_letter',245                         '/members/{id}/direct_debit_letter',246                         factory='..model.Member.context_factory')247        config.add_route('become_member_letter',248                         '/members/{id}/become_member_letter',249                         factory='..model.Member.context_factory')250        config.add_route('mv_entrance_list', '/members/mv_entrance_list')251        config.add_route('energy_meter_export', '/electricity/export')252        config.add_route('energy_meter_import', '/electricity/import')253        config.add_route('calculate_energy_values',254                         '/electricity/calculate_energy_values')255        config.add_route('access_authority', '/access_authority')256        config.add_route('access_authority_detail',257                         '/access_authority/{id}/list',258                         factory='.authority.AuthorityContext.context_factory')259        config.add_route('access_authority_detail_add',260                         '/access_authority/{id}/list/add',261                         factory='.authority.AuthorityContext.context_factory')262        config.add_route(263            'access_authority_detail_edit',264            '/access_authority/{viewname}/list/{id}/edit',265            factory='..model.AccessAuthority.context_factory')266        config.add_route(267            'access_authority_detail_delete',268            '/access_authority/{viewname}/list/{id}/delete',269            factory='..model.AccessAuthority.context_factory')270        config.add_route('energy_price', '/energy_price')271        config.add_route('electricity_list', '/electricity')272        config.add_route('global_energy_value_list', '/electricity_billing')273        config.add_route('energy_value_list',274                         '/electricity/{id}/history',275                         factory='..electricity.ElectricMeter.context_factory')276        config.add_route('advance_pay_value_list',277                         '/electricity/{id}/advance_pay_history',278                         factory='..electricity.ElectricMeter.context_factory')279        config.add_route('externals', '/externals')280        config.add_route('external_add', '/externals/add')281        config.add_route('external_edit', '/externals/{id}/edit',282                         factory='..mail.ExternalRecipient.context_factory')283        config.add_route('external_delete', '/externals/{id}/delete',284                         factory='..mail.ExternalRecipient.context_factory')285        config.add_route('bulletins', '/bulletins')286        config.add_route('bulletin_add', '/bulletins/add')287        config.add_route('bulletin_edit', '/bulletins/{id}/edit',288                         factory='..bulletins.Bulletin.context_factory')289        config.add_route('bulletin_delete', '/bulletins/{id}/delete',290                         factory='..bulletins.Bulletin.context_factory')291        config.add_route('bulletin_print', '/bulletins/{id}/print',292                         factory='..bulletins.Bulletin.context_factory')293        config.add_route('keylists', '/keylists')294        config.add_route('keylist_add', '/keylists/add')295        config.add_route('keylist_edit', '/keylists/{id}/edit',296                         factory='..keylist.Keylist.context_factory')297        config.add_route('keylist_delete', '/keylists/{id}/delete',298                         factory='..keylist.Keylist.context_factory')299        config.add_route('keys', '/keylists/{id}/keys',300                         factory='..keylist.Keylist.context_factory')301        config.add_route('key_add', '/keylists/{id}/keys/add',302                         factory='..keylist.Keylist.context_factory')303        config.add_route(304            'key_edit',305            '/keylists/{keylist_id}/keys/{id}/edit',306            factory='..keylist.Key.context_factory')307        config.add_route(308            'key_delete',309            '/keylists/{keylist_id}/keys/{id}/delete',310            factory='..keylist.Key.context_factory')311        config.add_route('keylist_attachment_add',312                         '/keylists/{id}/attachments/add',313                         factory='..keylist.Keylist.context_factory')314        config.add_route('keylist_attachment', '/keylists/{id}/attachments',315                         factory='..keylist.Keylist.context_factory')316        config.add_route(317            'keylist_attachment_download',318            '/keylists/{keylist_id}/attachments/{id}/download',319            factory='..keylist.KeylistAttachment.context_factory')320        config.add_route('protocols', '/protocols')321        config.add_route('protocol_add', '/protocols/add')322        config.add_route('protocol_edit', '/protocols/{id}/edit',323                         factory='..protocol.Protocol.context_factory')324        config.add_route('protocol_delete', '/protocols/{id}/delete',325                         factory='..protocol.Protocol.context_factory')326        config.add_route('protocol_detail', '/protocols/{id}/details',327                         factory='..protocol.Protocol.context_factory')328        config.add_route('protocol_detail_add', '/protocols/{id}/details/add',329                         factory='..protocol.Protocol.context_factory')330        config.add_route(331            'protocol_detail_edit',332            '/protocols/{protocol_id}/details/{id}/edit',333            factory='..protocol.ProtocolDetail.context_factory')334        config.add_route(335            'protocol_detail_delete',336            '/protocols/{protocol_id}/details/{id}/delete',337            factory='..protocol.ProtocolDetail.context_factory')338        config.add_route('protocol_print', '/protocols/{id}/print',339                         factory='..protocol.Protocol.context_factory')340        config.add_route('protocol_attachment_add',341                         '/protocols/{id}/attachments/add',342                         factory='..protocol.Protocol.context_factory')343        config.add_route('protocol_attachment', '/protocols/{id}/attachments',344                         factory='..protocol.Protocol.context_factory')345        config.add_route(346            'protocol_attachment_download',347            '/protocols/{protocol_id}/attachments/{id}/download',348            factory='..protocol.ProtocolAttachment.context_factory')349        config.add_route(350            'protocol_attachment_delete',351            '/protocols/{protocol_id}/attachments/{id}/delete',352            factory='..protocol.ProtocolAttachment.context_factory')353        config.add_route('protocol_commitment', '/protocols/{id}/commitments',354                         factory='..protocol.Protocol.context_factory')355        config.add_route('protocol_commitment_add',356                         '/protocols/{id}/commitments/add',357                         factory='..protocol.Protocol.context_factory')358        config.add_route(359            'protocol_commitment_edit',360            '/protocols/{protocol_id}/commitments/{id}/edit',361            factory='..protocol.ProtocolCommitment.context_factory')362        config.add_route(363            'protocol_commitment_delete',364            '/protocols/{protocol_id}/commitments/{id}/delete',365            factory='..protocol.ProtocolCommitment.context_factory')366        config.add_route('assignments', '/assignments')367        config.add_route('assignment_add', '/assignments/add')368        config.add_route('assignment_edit', '/assignments/{id}/edit',369                         factory='..assignment.Assignment.context_factory')370        config.add_route('assignment_delete', '/assignments/{id}/delete',371                         factory='..assignment.Assignment.context_factory')372        config.add_route('assignment_list_attendees', '/assignments/{id}/list',373                         factory='..assignment.Assignment.context_factory')374        config.add_route('assignment_attendees_add',375                         '/assignments/{id}/attendees/add',376                         factory='..assignment.Assignment.context_factory')377        config.add_route(378            'assignment_attendees_edit',379            '/assignments/{assignment_id}/attendees/{id}/edit',380            factory='..assignment.AssignmentAttendee.context_factory')381        config.add_route(382            'assignment_attendees_delete',383            '/assignments/{assignment_id}/attendees/{id}/delete',384            factory='..assignment.AssignmentAttendee.context_factory')385        config.add_route('depots', '/depots')386        config.add_route('depot_add', '/depots/add')387        config.add_route('depot_edit', '/depots/{id}/edit',388                         factory='..depot.Depot.context_factory')389        config.add_route('depot_delete', '/depots/{id}/delete',390                         factory='..depot.Depot.context_factory')391        config.add_route('depot_download', '/depots/{id}/download',392                         factory='..depot.Depot.context_factory')393    @property394    def pipeline(self):395        return [396            (DenyFrame, 'factory', None, {}),397            (NoCache, 'factory', None, {}),398        ]399    def make_wsgi_app(self, global_config):400        app = self.config.make_wsgi_app()401        for spec, protocol, name, extra in self.pipeline:402            if protocol == 'factory':403                app = spec(app, **extra)404                continue405            entrypoint = pkg_resources.get_entry_info(spec, protocol, name)406            app = entrypoint.load()(app, global_config, **extra)407        return app408factory = Portal()409@pyramid.view.view_config(410    context=Exception,411    permission=NO_PERMISSION_REQUIRED,412    renderer='json')413class Error(sw.allotmentclub.browser.base.View):414    title = u'Interner Server-Fehler'415    status_code = 500416    def __init__(self, context, request):417        super(Error, self).__init__(context, request)418        self.time = time.time()419    @property420    def show_traceback(self):421        return self.request.registry.settings['testing']422    @property423    def exc_line(self):424        return traceback.format_exception_only(425            type(self.context), self.context)[0].strip()426    @property427    def error_ref(self):428        return (str(int(self.time))[-4:] +429                str(int(hashlib.sha1(430                    self.tb.encode('utf-8')).hexdigest(), 16))[:4])431    def update(self):432        self.tb = traceback.format_exc()433        self.error_summary = ('Ref: %s %s', self.error_ref, self.exc_line)434        self.request.response.status_code = self.status_code435        self.log()436    def log(self):437        error_log.error(*self.error_summary)438        for line in self.tb.splitlines():439            error_log.info(line, log_request=False)440        if self.show_traceback:441            print('Exception raised during test: {}'.format(self.tb))442@pyramid.view.view_config(443    route_name='sentry_frontend',444    permission=NO_PERMISSION_REQUIRED,445    renderer='json')446class SentryDataView(sw.allotmentclub.browser.base.View):447    def __call__(self):448        settings = pyramid.threadlocal.get_current_registry().settings449        return dict(dsn=settings.get('sentry.frontenddsn', ''))450@pyramid.view.view_config(451    context=pyramid.httpexceptions.HTTPException,452    permission=NO_PERMISSION_REQUIRED)453def HTTPException(context, request):454    return context455@pyramid.view.view_config(456    context=pyramid.httpexceptions.HTTPError,457    permission=NO_PERMISSION_REQUIRED,458    renderer='json')459class HTTPError(Error):460    @property461    def title(self):462        return '%s %s' % (self.status_code, type(self.context).__name__)463    @property464    def status_code(self):465        return self.context.status_code466@pyramid.view.notfound_view_config(renderer='json')467class NotFound(HTTPError):468    def log(self):469        if self.request.user.authenticated:470            log_with_user(471                auth_log.warning, self.request.user,472                'Ref: %s User %s tried to access non-existing url %s',473                self.error_ref, self.request.user.username, self.request.url)474        else:475            log_with_user(476                auth_log.warning, self.request.user,477                'Ref: %s Unauthenticated user tried to access '478                'non-existing url %s', self.error_ref, self.request.url)479@pyramid.events.subscriber(pyramid.events.ApplicationCreated)480def log_start(event):481    app_log.info('Application successfully started.')482shutdown_already_logged = False483def log_shutdown(signalnum, frame):484    global shutdown_already_logged485    if not shutdown_already_logged:486        shutdown_already_logged = True487        app_log.info('Application shutdown.')488    if signalnum == signal.SIGINT:489        # Make sure the port is closed, too:490        orig_sigint_handler(signalnum, frame)491signal.signal(signal.SIGTERM, log_shutdown)...test_context_factory.py
Source:test_context_factory.py  
...11    pass12class TestContextFactoryLocal(object):13    def test_lack_requirement(self):14        self.custom_context = dict(test='context')15        @hug.context_factory()16        def return_context(**kwargs):17            return self.custom_context18        @hug.delete_context()19        def delete_context(context, exception=None, errors=None, lacks_requirement=None):20            assert context == self.custom_context21            assert not exception22            assert not errors23            assert lacks_requirement24            assert isinstance(lacks_requirement, RequirementFailed)25            self.custom_context['launched_delete_context'] = True26        def test_local_requirement(**kwargs):27            assert 'context' in kwargs28            assert kwargs['context'] == self.custom_context29            self.custom_context['launched_requirement'] = True30            return RequirementFailed()31        @hug.local(requires=test_local_requirement)32        def requirement_local_function():33            self.custom_context['launched_local_function'] = True34        requirement_local_function()35        assert 'launched_local_function' not in self.custom_context36        assert 'launched_requirement' in self.custom_context37        assert 'launched_delete_context' in self.custom_context38    def test_directive(self):39        custom_context = dict(test='context')40        @hug.context_factory()41        def return_context(**kwargs):42            return custom_context43        @hug.delete_context()44        def delete_context(context, **kwargs):45            pass46        @hug.directive()47        def custom_directive(**kwargs):48            assert 'context' in kwargs49            assert kwargs['context'] == custom_context50            return 'custom'51        @hug.local()52        def directive_local_function(custom: custom_directive):53            assert custom == 'custom'54        directive_local_function()55    def test_validation(self):56        custom_context = dict(test='context', not_valid_number=43)57        @hug.context_factory()58        def return_context(**kwargs):59            return custom_context60        @hug.delete_context()61        def delete_context(context, exception=None, errors=None, lacks_requirement=None):62            assert context == custom_context63            assert not exception64            assert errors65            assert not lacks_requirement66            custom_context['launched_delete_context'] = True67        def test_requirement(**kwargs):68            assert 'context' in kwargs69            assert kwargs['context'] == custom_context70            custom_context['launched_requirement'] = True71            return RequirementFailed()72        @hug.type(extend=hug.types.number, accept_context=True)73        def custom_number_test(value, context):74            assert context == custom_context75            if value == context['not_valid_number']:76                raise ValueError('not valid number')77            return value78        @hug.local()79        def validation_local_function(value: custom_number_test):80            custom_context['launched_local_function'] = value81        validation_local_function(43)82        assert not 'launched_local_function' in custom_context83        assert 'launched_delete_context' in custom_context84    def test_transform(self):85        custom_context = dict(test='context', test_number=43)86        @hug.context_factory()87        def return_context(**kwargs):88            return custom_context89        @hug.delete_context()90        def delete_context(context, exception=None, errors=None, lacks_requirement=None):91            assert context == custom_context92            assert not exception93            assert not errors94            assert not lacks_requirement95            custom_context['launched_delete_context'] = True96        class UserSchema(Schema):97            name = fields.Str()98            @post_dump()99            def check_context(self, data):100                assert self.context['test'] == 'context'101                self.context['test_number'] += 1102        @hug.local()103        def validation_local_function() -> UserSchema():104            return {'name': 'test'}105        validation_local_function()106        assert 'test_number' in custom_context and custom_context['test_number'] == 44107        assert 'launched_delete_context' in custom_context108    def test_exception(self):109        custom_context = dict(test='context')110        @hug.context_factory()111        def return_context(**kwargs):112            return custom_context113        @hug.delete_context()114        def delete_context(context, exception=None, errors=None, lacks_requirement=None):115            assert context == custom_context116            assert exception117            assert isinstance(exception, CustomException)118            assert not errors119            assert not lacks_requirement120            custom_context['launched_delete_context'] = True121        @hug.local()122        def exception_local_function():123            custom_context['launched_local_function'] = True124            raise CustomException()125        with pytest.raises(CustomException):126            exception_local_function()127        assert 'launched_local_function' in custom_context128        assert 'launched_delete_context' in custom_context129    def test_success(self):130        custom_context = dict(test='context')131        @hug.context_factory()132        def return_context(**kwargs):133            return custom_context134        @hug.delete_context()135        def delete_context(context, exception=None, errors=None, lacks_requirement=None):136            assert context == custom_context137            assert not exception138            assert not errors139            assert not lacks_requirement140            custom_context['launched_delete_context'] = True141        @hug.local()142        def success_local_function():143            custom_context['launched_local_function'] = True144        success_local_function()145        assert 'launched_local_function' in custom_context146        assert 'launched_delete_context' in custom_context147class TestContextFactoryCLI(object):148    def test_lack_requirement(self):149        custom_context = dict(test='context')150        @hug.context_factory()151        def return_context(**kwargs):152            return custom_context153        @hug.delete_context()154        def delete_context(context, exception=None, errors=None, lacks_requirement=None):155            assert context == custom_context156            assert not exception157            assert not errors158            assert lacks_requirement159            assert isinstance(lacks_requirement, RequirementFailed)160            custom_context['launched_delete_context'] = True161        def test_requirement(**kwargs):162            assert 'context' in kwargs163            assert kwargs['context'] == custom_context164            custom_context['launched_requirement'] = True165            return RequirementFailed()166        @hug.cli(requires=test_requirement)167        def requirement_local_function():168            custom_context['launched_local_function'] = True169        hug.test.cli(requirement_local_function)170        assert 'launched_local_function' not in custom_context171        assert 'launched_requirement' in custom_context172        assert 'launched_delete_context' in custom_context173    def test_directive(self):174        custom_context = dict(test='context')175        @hug.context_factory()176        def return_context(**kwargs):177            return custom_context178        @hug.delete_context()179        def delete_context(context, **kwargs):180            pass181        @hug.directive()182        def custom_directive(**kwargs):183            assert 'context' in kwargs184            assert kwargs['context'] == custom_context185            return 'custom'186        @hug.cli()187        def directive_local_function(custom: custom_directive):188            assert custom == 'custom'189        hug.test.cli(directive_local_function)190    def test_validation(self):191        custom_context = dict(test='context', not_valid_number=43)192        @hug.context_factory()193        def return_context(**kwargs):194            return custom_context195        @hug.delete_context()196        def delete_context(context, exception=None, errors=None, lacks_requirement=None):197            assert not exception198            assert context == custom_context199            assert errors200            assert not lacks_requirement201            custom_context['launched_delete_context'] = True202        def test_requirement(**kwargs):203            assert 'context' in kwargs204            assert kwargs['context'] == custom_context205            custom_context['launched_requirement'] = True206            return RequirementFailed()207        @hug.type(extend=hug.types.number, accept_context=True)208        def new_custom_number_test(value, context):209            assert context == custom_context210            if value == context['not_valid_number']:211                raise ValueError('not valid number')212            return value213        @hug.cli()214        def validation_local_function(value: hug.types.number):215            custom_context['launched_local_function'] = value216            return 0217        with pytest.raises(SystemExit):218            hug.test.cli(validation_local_function, 'xxx')219        assert 'launched_local_function' not in custom_context220        assert 'launched_delete_context' in custom_context221    def test_transform(self):222        custom_context = dict(test='context', test_number=43)223        @hug.context_factory()224        def return_context(**kwargs):225            return custom_context226        @hug.delete_context()227        def delete_context(context, exception=None, errors=None, lacks_requirement=None):228            assert not exception229            assert context == custom_context230            assert not errors231            assert not lacks_requirement232            custom_context['launched_delete_context'] = True233        class UserSchema(Schema):234            name = fields.Str()235            @post_dump()236            def check_context(self, data):237                assert self.context['test'] == 'context'238                self.context['test_number'] += 1239        @hug.cli()240        def transform_cli_function() -> UserSchema():241            custom_context['launched_cli_function'] = True242            return {'name': 'test'}243        hug.test.cli(transform_cli_function)244        assert 'launched_cli_function' in custom_context245        assert 'launched_delete_context' in custom_context246        assert 'test_number' in custom_context247        assert custom_context['test_number'] == 44248    def test_exception(self):249        custom_context = dict(test='context')250        @hug.context_factory()251        def return_context(**kwargs):252            return custom_context253        @hug.delete_context()254        def delete_context(context, exception=None, errors=None, lacks_requirement=None):255            assert context == custom_context256            assert exception257            assert isinstance(exception, CustomException)258            assert not errors259            assert not lacks_requirement260            custom_context['launched_delete_context'] = True261        @hug.cli()262        def exception_local_function():263            custom_context['launched_local_function'] = True264            raise CustomException()265        hug.test.cli(exception_local_function)266        assert 'launched_local_function' in custom_context267        assert 'launched_delete_context' in custom_context268    def test_success(self):269        custom_context = dict(test='context')270        @hug.context_factory()271        def return_context(**kwargs):272            return custom_context273        @hug.delete_context()274        def delete_context(context, exception=None, errors=None, lacks_requirement=None):275            assert context == custom_context276            assert not exception277            assert not errors278            assert not lacks_requirement279            custom_context['launched_delete_context'] = True280        @hug.cli()281        def success_local_function():282            custom_context['launched_local_function'] = True283        hug.test.cli(success_local_function)284        assert 'launched_local_function' in custom_context285        assert 'launched_delete_context' in custom_context286class TestContextFactoryHTTP(object):287    def test_lack_requirement(self):288        custom_context = dict(test='context')289        @hug.context_factory()290        def return_context(**kwargs):291            return custom_context292        @hug.delete_context()293        def delete_context(context, exception=None, errors=None, lacks_requirement=None):294            assert context == custom_context295            assert not exception296            assert not errors297            assert lacks_requirement298            custom_context['launched_delete_context'] = True299        def test_requirement(**kwargs):300            assert 'context' in kwargs301            assert kwargs['context'] == custom_context302            custom_context['launched_requirement'] = True303            return 'requirement_failed'304        @hug.get('/requirement_function', requires=test_requirement)305        def requirement_http_function():306            custom_context['launched_local_function'] = True307        hug.test.get(module, '/requirement_function')308        assert 'launched_local_function' not in custom_context309        assert 'launched_requirement' in custom_context310        assert 'launched_delete_context' in custom_context311    def test_directive(self):312        custom_context = dict(test='context')313        @hug.context_factory()314        def return_context(**kwargs):315            return custom_context316        @hug.delete_context()317        def delete_context(context, **kwargs):318            pass319        @hug.directive()320        def custom_directive(**kwargs):321            assert 'context' in kwargs322            assert kwargs['context'] == custom_context323            return 'custom'324        @hug.get('/directive_function')325        def directive_http_function(custom: custom_directive):326            assert custom == 'custom'327        hug.test.get(module, '/directive_function')328    def test_validation(self):329        custom_context = dict(test='context', not_valid_number=43)330        @hug.context_factory()331        def return_context(**kwargs):332            return custom_context333        @hug.delete_context()334        def delete_context(context, exception=None, errors=None, lacks_requirement=None):335            assert context == custom_context336            assert not exception337            assert errors338            assert not lacks_requirement339            custom_context['launched_delete_context'] = True340        def test_requirement(**kwargs):341            assert 'context' in kwargs342            assert kwargs['context'] == custom_context343            custom_context['launched_requirement'] = True344            return RequirementFailed()345        @hug.type(extend=hug.types.number, accept_context=True)346        def custom_number_test(value, context):347            assert context == custom_context348            if value == context['not_valid_number']:349                raise ValueError('not valid number')350            return value351        @hug.get('/validation_function')352        def validation_http_function(value: custom_number_test):353            custom_context['launched_local_function'] = value354        hug.test.get(module, '/validation_function', 43)355        assert 'launched_local_function ' not in custom_context356        assert 'launched_delete_context' in custom_context357    def test_transform(self):358        custom_context = dict(test='context', test_number=43)359        @hug.context_factory()360        def return_context(**kwargs):361            return custom_context362        @hug.delete_context()363        def delete_context(context, exception=None, errors=None, lacks_requirement=None):364            assert context == custom_context365            assert not exception366            assert not errors367            assert not lacks_requirement368            custom_context['launched_delete_context'] = True369        class UserSchema(Schema):370            name = fields.Str()371            @post_dump()372            def check_context(self, data):373                assert self.context['test'] == 'context'374                self.context['test_number'] += 1375        @hug.get('/validation_function')376        def validation_http_function() -> UserSchema():377            custom_context['launched_local_function'] = True378        hug.test.get(module, '/validation_function', 43)379        assert 'launched_local_function' in custom_context380        assert 'launched_delete_context' in custom_context381        assert 'test_number' in custom_context382        assert custom_context['test_number'] == 44383    def test_exception(self):384        custom_context = dict(test='context')385        @hug.context_factory()386        def return_context(**kwargs):387            return custom_context388        @hug.delete_context()389        def delete_context(context, exception=None, errors=None, lacks_requirement=None):390            assert context == custom_context391            assert exception392            assert isinstance(exception, CustomException)393            assert not errors394            assert not lacks_requirement395            custom_context['launched_delete_context'] = True396        @hug.get('/exception_function')397        def exception_http_function():398            custom_context['launched_local_function'] = True399            raise CustomException()400        with pytest.raises(CustomException):401            hug.test.get(module, '/exception_function')402        assert 'launched_local_function' in custom_context403        assert 'launched_delete_context' in custom_context404    def test_success(self):405        custom_context = dict(test='context')406        @hug.context_factory()407        def return_context(**kwargs):408            return custom_context409        @hug.delete_context()410        def delete_context(context, exception=None, errors=None, lacks_requirement=None):411            assert context == custom_context412            assert not exception413            assert not errors414            assert not lacks_requirement415            custom_context['launched_delete_context'] = True416        @hug.get('/success_function')417        def success_http_function():418            custom_context['launched_local_function'] = True419        hug.test.get(module, '/success_function')420        assert 'launched_local_function' in custom_context...TestMenuHandlers.py
Source:TestMenuHandlers.py  
1import os2import unittest3from pathlib import Path4from unittest.mock import MagicMock5from unittest.mock import Mock6from pygame import font7from gameplay.keys import GameKeys8from gameplay.keys import KeyMapper9from screens.disposition_code import MenuAction10from screens.menu_handlers import KeySettingMenuContext11from screens.menu_handlers import MenuContextFactory12from screens.menu_handlers import MusicSelectionMenuContext13from screens.menu_handlers import OptionsMenuContext14from screens.menu_renderer import LazyTextRenderer15from screens.menu_renderer import StandardTextRenderer16# TODO: it probably makes sense to have separate test classes for each of the MenuContexts17class TestTopLevelMenu(unittest.TestCase):18    def setUp(self):19        self.jukebox = Mock()20        self.key_change_publisher = Mock()21        # I could mock these but the real thing is really just a wrapper around a dict, so whatever22        self.game_keys = GameKeys()23        self.key_mapper = KeyMapper(self.game_keys)24        # I could put a font file as a test resource but it's just as easy to change the test if I change the real fonts25        self.font_file = self._get_test_font_file()26        self.screen = MagicMock()27        font.init()28        self.context_factory = MenuContextFactory(29            self.jukebox, self.key_change_publisher, self.game_keys,30            self.key_mapper, self.font_file, self.screen)31    def test_toplevelmenu_labels(self):32        expected_labels = ["New Game", "High Scores", "Options", "Quit"]33        menu = self.context_factory.build_top_level_menu_screen(False)34        actual_labels = menu.get_render_info().get_labels()35        self.assertListEqual(expected_labels, actual_labels)36    def test_toplevelmenu_wrap_navigation(self):37        menu = self.context_factory.build_top_level_menu_screen(False)38        self.assertEqual(0, menu.get_selected_index())39        menu.move_to_previous_option()40        self.assertEqual(3, menu.get_selected_index())41        menu.move_to_next_option()42        self.assertEqual(0, menu.get_selected_index())43    def test_toplevelmenu_execute_play_game(self):44        menu = self.context_factory.build_top_level_menu_screen(False)45        self.assertEqual(0, menu.get_selected_index())46        next_state = menu.execute_current_option()47        self.assertEqual(menu, next_state.active_menu_screen)48        self.assertEqual(MenuAction.PLAY_GAME, next_state.get_menu_action())49    def test_toplevelmenu_execute_high_scores(self):50        menu = self.context_factory.build_top_level_menu_screen(False)51        self.move_down_n(1, menu)52        next_state = menu.execute_current_option()53        self.assertEqual(menu, next_state.active_menu_screen)54        self.assertEqual(MenuAction.SHOW_HIGH_SCORES, next_state.get_menu_action())55    def test_toplevelmenu_execute_options(self):56        menu = self.context_factory.build_top_level_menu_screen(False)57        self.move_down_n(2, menu)58        next_state = menu.execute_current_option()59        self.assertIsInstance(next_state.active_menu_screen, OptionsMenuContext)60    def test_toplevelmenu_execute_quit(self):61        menu = self.context_factory.build_top_level_menu_screen(False)62        self.move_down_n(3, menu)63        next_state = menu.execute_current_option()64        self.assertEqual(menu, next_state.active_menu_screen)65        self.assertEqual(MenuAction.QUIT, next_state.get_menu_action())66    def test_toplevelmenu_not_listening_for_key(self):67        menu = self.context_factory.build_top_level_menu_screen(False)68        self.assertFalse(menu.is_listening_for_key())69    def test_toplevelmenu_render_info(self):70        menu = self.context_factory.build_top_level_menu_screen(False)71        render_info = menu.get_render_info()72        self.assertIsInstance(render_info.get_text_renderer(), StandardTextRenderer)73    def test_pausedmenu_labels(self):74        expected_labels = ["Resume Game", "New Game", "High Scores", "Options", "Quit"]75        menu = self.context_factory.build_top_level_menu_screen(True)76        actual_labels = menu.get_render_info().get_labels()77        self.assertListEqual(expected_labels, actual_labels)78    def test_pausedmenu_execute_resume_game(self):79        menu = self.context_factory.build_top_level_menu_screen(True)80        self.assertEqual(0, menu.get_selected_index())81        next_state = menu.execute_current_option()82        self.assertEqual(menu, next_state.active_menu_screen)83        self.assertEqual(MenuAction.PLAY_GAME, next_state.get_menu_action())84    def test_pausedmenu_execute_new_game(self):85        menu = self.context_factory.build_top_level_menu_screen(True)86        self.move_down_n(1, menu)87        next_state = menu.execute_current_option()88        self.assertEqual(menu, next_state.active_menu_screen)89        self.assertEqual(MenuAction.NEW_GAME, next_state.get_menu_action())90    def test_paused_menu_execute_high_scores(self):91        menu = self.context_factory.build_top_level_menu_screen(True)92        self.move_down_n(2, menu)93        next_state = menu.execute_current_option()94        self.assertEqual(menu, next_state.active_menu_screen)95        self.assertEqual(MenuAction.SHOW_HIGH_SCORES, next_state.get_menu_action())96    def test_paused_menu_execute_options(self):97        menu = self.context_factory.build_top_level_menu_screen(True)98        self.move_down_n(3, menu)99        next_state = menu.execute_current_option()100        self.assertIsInstance(next_state.active_menu_screen, OptionsMenuContext)101    def test_paused_menu_execute_quit(self):102        menu = self.context_factory.build_top_level_menu_screen(True)103        self.move_down_n(4, menu)104        next_state = menu.execute_current_option()105        self.assertEqual(menu, next_state.active_menu_screen)106        self.assertEqual(MenuAction.QUIT, next_state.get_menu_action())107    def test_pausedmenu_not_listening_for_key(self):108        menu = self.context_factory.build_top_level_menu_screen(True)109        self.assertFalse(menu.is_listening_for_key())110    def test_pausedmenu_render_info(self):111        menu = self.context_factory.build_top_level_menu_screen(True)112        render_info = menu.get_render_info()113        self.assertIsInstance(render_info.get_text_renderer(), StandardTextRenderer)114    def test_musicmenu_labels(self):115        songlist = ["Song 1", "Song 2", "Song 3"]116        self.jukebox.get_available_song_titles.return_value = songlist117        menu = self.context_factory.build_music_selection_screen()118        self.assertEqual(songlist, menu.get_render_info().get_labels())119    def test_musicmenu_no_songs(self):120        self.jukebox.get_available_song_titles.return_value = []121        menu = self.context_factory.build_music_selection_screen()122        self.assertEqual([], menu.get_render_info().get_labels())123        self.assertEqual(0, menu.get_selected_index())124        menu.move_to_next_option()125        self.assertEqual(0, menu.get_selected_index())126    def test_musicmenu_execute_song_selection(self):127        songlist = ["Song 1", "Song 2", "Song 3"]128        self.jukebox.get_available_song_titles.return_value = songlist129        menu = self.context_factory.build_music_selection_screen()130        next_state = menu.execute_current_option()131        self.assertEqual(menu, next_state.get_active_menu_screen())132        self.assertEqual(MenuAction.MENU, next_state.get_menu_action())133        self.jukebox.set_song.assert_called_once_with("Song 1")134    def test_musicmenu_not_listening_for_key(self):135        self.jukebox.get_available_song_titles.return_value = ['Song 1']136        menu = self.context_factory.build_music_selection_screen()137        self.assertFalse(menu.is_listening_for_key())138    def test_musicmenu_render_info(self):139        self.jukebox.get_available_song_titles.return_value = []140        menu = self.context_factory.build_music_selection_screen()141        self.assertIsInstance(menu.get_render_info().get_text_renderer(), StandardTextRenderer)142    def test_keymenu_default_labels(self):143        menu = self.context_factory.build_key_changing_screen()144        actual_labels = menu.get_labels()145        expected_labels = self.default_key_labels()146        self.assertEqual(expected_labels, actual_labels)147    def test_keymenu_not_listening_for_key_by_default(self):148        menu = self.context_factory.build_key_changing_screen()149        self.assertFalse(menu.is_listening_for_key())150    def test_keymenu_listening_for_key_after_executing_option(self):151        menu = self.context_factory.build_key_changing_screen()152        menu.execute_current_option()153        self.assertTrue(menu.is_listening_for_key())154    def test_keymenu_update_left_key(self):155        self._run_key_update_test(0, 'J', 'Move Left: <J>')156    def test_keymenu_update_right_key(self):157        self._run_key_update_test(1, 'L', 'Move Right: <L>')158    def test_keymenu_update_down_key(self):159        self._run_key_update_test(2, 'K', 'Move Down: <K>')160    def test_keymenu_update_drop_key(self):161        self._run_key_update_test(3, 'Up', 'Drop Piece: <Up>')162    def test_keymenu_update_rot_left_key(self):163        self._run_key_update_test(4, 'One', 'Rotate Left: <One>')164    def test_keymenu_update_rot_right_key(self):165        self._run_key_update_test(5, 'Two', 'Rotate Right: <Two>')166    def _run_key_update_test(self, label_index, new_key_name, expected_label):167        menu = self.context_factory.build_key_changing_screen()168        self.move_down_n(label_index, menu)169        menu.execute_current_option()170        menu.handle_key_event(self.game_keys.by_name(new_key_name))171        expected_labels = self.default_key_labels()172        expected_labels[label_index] = expected_label173        self.assertEqual(expected_labels, menu.get_labels())174    def test_keymenu_updated_labels_are_cached(self):175        menu = self.context_factory.build_key_changing_screen()176        self.assertIs(menu.get_labels(), menu.get_labels(), 'Original labels should have been cached')177        menu.execute_current_option()178        menu.handle_key_event(self.game_keys.by_name('A'))179        self.assertIs(menu.get_labels(), menu.get_labels(), 'New labels should have been cached')180    def test_keymenu_render_info(self):181        menu = self.context_factory.build_key_changing_screen()182        self.assertEqual(self.default_key_labels(), menu.get_render_info().get_labels())183        self.assertIsInstance(menu.get_render_info().get_text_renderer(), LazyTextRenderer)184    def test_optionsmenu_default_labels(self):185        menu = self.context_factory.build_options_screen()186        self.assertEqual(self.default_options_labels(), menu.get_labels())187    def test_optionsmenu_sound_off_label(self):188        menu = self.context_factory.build_options_screen()189        menu.execute_current_option()190        expected = self.default_options_labels()191        expected[0] = "Sound On / [Off]"192        self.assertEqual(expected, menu.get_labels())193    def test_optionsmenu_music_off_label(self):194        menu = self.context_factory.build_options_screen()195        self.move_down_n(1, menu)196        menu.execute_current_option()197        expected = self.default_options_labels()198        expected[1] = "Music On / [Off]"199        self.assertEqual(expected, menu.get_labels())200    def test_optionsmenu_toggle_sound_twice(self):201        menu = self.context_factory.build_options_screen()202        menu.execute_current_option()203        menu.execute_current_option()204        self.assertEqual(self.default_options_labels(), menu.get_labels())205    def test_optionsmenu_toggle_music_twice(self):206        menu = self.context_factory.build_options_screen()207        self.move_down_n(1, menu)208        menu.execute_current_option()209        menu.execute_current_option()210        self.assertEqual(self.default_options_labels(), menu.get_labels())211    def test_optionsmenu_sound_toggle_returns_menu_state(self):212        menu = self.context_factory.build_options_screen()213        next_state = menu.execute_current_option()214        self.assertEqual(MenuAction.MENU, next_state.get_menu_action())215        self.assertEqual(menu, next_state.get_active_menu_screen())216    def test_optionsmenu_sound_toggle_affects_jukebox(self):217        menu = self.context_factory.build_options_screen()218        menu.execute_current_option()219        self.jukebox.enable_sound.assert_called_once_with(False)220        self.jukebox.reset_mock()221        menu.execute_current_option()222        self.jukebox.enable_sound.assert_called_once_with(True)223    def test_optionsmenu_music_toggle_returns_menu_state(self):224        menu = self.context_factory.build_options_screen()225        self.move_down_n(1, menu)226        next_state = menu.execute_current_option()227        self.assertEqual(MenuAction.MENU, next_state.get_menu_action())228        self.assertEqual(menu, next_state.get_active_menu_screen())229    def test_optionsmenu_music_toggle_affects_jukebox(self):230        menu = self.context_factory.build_options_screen()231        self.move_down_n(1, menu)232        menu.execute_current_option()233        self.jukebox.enable_music.assert_called_once_with(False)234        self.jukebox.reset_mock()235        menu.execute_current_option()236        self.jukebox.enable_music.assert_called_once_with(True)237    def test_optionsmenu_navigate_to_music_selection(self):238        self.jukebox.get_available_song_titles.return_value = ["Song 1"]239        menu = self.context_factory.build_options_screen()240        self.move_down_n(2, menu)241        next_state = menu.execute_current_option()242        self.assertEqual(MenuAction.MENU, next_state.get_menu_action())243        returned_submenu = next_state.get_active_menu_screen()244        self.assertIsInstance(returned_submenu, MusicSelectionMenuContext)245        self.assertEqual(["Song 1"], returned_submenu.get_render_info().get_labels(),246                         "Options menu should have passed the correct songs to the submenu")247    def test_optionsmenu_navigate_to_key_menu(self):248        menu = self.context_factory.build_options_screen()249        self.move_down_n(3, menu)250        next_state = menu.execute_current_option()251        self.assertEqual(MenuAction.MENU, next_state.get_menu_action())252        returned_submenu = next_state.get_active_menu_screen()253        self.assertIsInstance(returned_submenu, KeySettingMenuContext)254    @staticmethod255    def move_down_n(n, menu):256        """ A helper for setting the menu selection index """257        for _ in range(n):258            menu.move_to_next_option()259    @staticmethod260    def default_key_labels():261        return [262            'Move Left: <Left>',263            'Move Right: <Right>',264            'Move Down: <Down>',265            'Drop Piece: <Space>',266            'Rotate Left: <Z>',267            'Rotate Right: <X>'268        ]269    @staticmethod270    def default_options_labels():271        return [272            "Sound [On] / Off",273            "Music [On] / Off",274            "Change Song",275            "Change Keys"]276    @staticmethod277    def _get_test_font_file():278        current_path = Path(os.path.dirname(os.path.realpath(__file__)))...test_case_test.py
Source:test_case_test.py  
...16from checkers import asserts17from checkers import test_case18from checkers import test_result19from checkers.runners import pyunit20def _dummy_context_factory(tc):21  return checkers.Context(tc, None)22@checkers.test23def _dummy_test():24  pass25@checkers.test26def test_test_case_init():27  test = _dummy_test28  context_factory = _dummy_context_factory29  tc = test_case.TestCase(test, context_factory)30  asserts.are_equal(tc.name, '_dummy_test')31  asserts.are_equal(tc.full_name, 'test_case_test._dummy_test')32  asserts.are_same(tc.test, test)33  asserts.is_not_none(tc.context)34  asserts.is_empty(tc.description)...LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!
