• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

iplweb / bpp / ba6f9e1f-4683-40a1-aae1-40dd0fcb64e3

25 Aug 2025 06:57PM UTC coverage: 43.284% (+0.6%) from 42.715%
ba6f9e1f-4683-40a1-aae1-40dd0fcb64e3

push

circleci

mpasternak
Merge branch 'release/v202508.1208'

77 of 961 new or added lines in 27 files covered. (8.01%)

731 existing lines in 54 files now uncovered.

17273 of 39906 relevant lines covered (43.28%)

0.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.41
src/bpp/tests/util.py
1
"""Ten moduł zawiera 'normalne', dla ludzi funkcje, które mogą być używane
2
do ustawiania testów."""
3

4
from __future__ import annotations
2✔
5

6
import cgi
2✔
7
import random
2✔
8
import re
2✔
9
import time
2✔
10
import warnings
2✔
11
from datetime import datetime
2✔
12

13
from django.http import HttpResponse
2✔
14
from django.urls import reverse
2✔
15
from model_bakery import baker
2✔
16
from selenium.webdriver.common.keys import Keys
2✔
17
from selenium.webdriver.support.expected_conditions import visibility_of
2✔
18
from selenium.webdriver.support.wait import WebDriverWait
2✔
19
from splinter.exceptions import ElementDoesNotExist
2✔
20

21
from bpp.models import (
2✔
22
    Autor,
23
    Charakter_Formalny,
24
    Jednostka,
25
    Jezyk,
26
    Patent,
27
    Praca_Doktorska,
28
    Praca_Habilitacyjna,
29
    Typ_KBN,
30
    Tytul,
31
    Uczelnia,
32
    Wydawnictwo_Ciagle,
33
    Wydawnictwo_Zwarte,
34
    Wydzial,
35
    Zrodlo,
36
)
37
from bpp.models.system import Status_Korekty
2✔
38

39
from django_bpp.selenium_util import (
2✔
40
    LONG_WAIT_TIME,
41
    SHORT_WAIT_TIME,
42
    wait_for,
43
    wait_for_page_load,
44
)
45

46

47
def setup_model_bakery():
2✔
48
    baker.generators.add(
2✔
49
        "django.contrib.postgres.fields.array.ArrayField", lambda x: []
50
    )
51

52
    baker.generators.add(
2✔
53
        "django.contrib.postgres.search.SearchVectorField", lambda x=None: None
54
    )
55

56

57
def set_default(varname, value, dct):
2✔
UNCOV
58
    if varname not in dct:
×
UNCOV
59
        dct[varname] = value
×
60

61

62
def any_autor(nazwisko="Kowalski", imiona="Jan Maria", tytul="dr", **kw):
2✔
UNCOV
63
    tytul = Tytul.objects.get_or_create(skrot=tytul)[0]
×
UNCOV
64
    return Autor.objects.create(nazwisko=nazwisko, tytul=tytul, imiona=imiona, **kw)
×
65

66

67
def any_uczelnia(nazwa="Uczelnia", skrot="UCL"):
2✔
68
    return Uczelnia.objects.create(nazwa=nazwa, skrot=skrot)
×
69

70

71
wydzial_cnt = 0
2✔
72

73

74
def any_wydzial(nazwa=None, skrot=None, uczelnia_skrot="UCL", **kw):
2✔
75
    global wydzial_cnt
76
    try:
×
77
        uczelnia = Uczelnia.objects.get(skrot=uczelnia_skrot)
×
78
    except Uczelnia.DoesNotExist:
×
79
        uczelnia = any_uczelnia()
×
80

81
    if nazwa is None:
×
82
        nazwa = "Wydział %s" % wydzial_cnt
×
83

84
    if skrot is None:
×
85
        skrot = "W%s" % wydzial_cnt
×
86

87
    wydzial_cnt += 1
×
88

89
    set_default("uczelnia", uczelnia, kw)
×
90
    return Wydzial.objects.create(nazwa=nazwa, skrot=skrot, **kw)
×
91

92

93
def any_jednostka(nazwa=None, skrot=None, wydzial_skrot="WDZ", **kw):
2✔
94
    """
95
    :rtype: bpp.models.Jednostka
96
    """
UNCOV
97
    if nazwa is None:
×
98
        nazwa = "Jednostka %s" % random.randint(0, 500000)
×
99

UNCOV
100
    if skrot is None:
×
UNCOV
101
        skrot = "J. %s" % random.randint(0, 5000000)
×
102

UNCOV
103
    try:
×
UNCOV
104
        uczelnia = kw.pop("uczelnia")
×
UNCOV
105
    except KeyError:
×
UNCOV
106
        uczelnia = Uczelnia.objects.all().first()
×
UNCOV
107
        if uczelnia is None:
×
UNCOV
108
            uczelnia = baker.make(Uczelnia)
×
109

UNCOV
110
    try:
×
UNCOV
111
        wydzial = kw.pop("wydzial")
×
UNCOV
112
    except KeyError:
×
UNCOV
113
        try:
×
UNCOV
114
            wydzial = Wydzial.objects.get(skrot=wydzial_skrot)
×
UNCOV
115
        except Wydzial.DoesNotExist:
×
UNCOV
116
            wydzial = baker.make(Wydzial, uczelnia=uczelnia)
×
117

UNCOV
118
    ret = Jednostka.objects.create(
×
119
        nazwa=nazwa, skrot=skrot, wydzial=wydzial, uczelnia=uczelnia, **kw
120
    )
UNCOV
121
    ret.refresh_from_db()
×
UNCOV
122
    return ret
×
123

124

125
CURRENT_YEAR = datetime.now().year
2✔
126

127

128
def any_wydawnictwo(klass, rok=None, **kw):
2✔
UNCOV
129
    if rok is None:
×
UNCOV
130
        rok = CURRENT_YEAR
×
131

UNCOV
132
    c = time.time()
×
UNCOV
133
    kl = str(klass).split(".")[-1].replace("'>", "")
×
134

UNCOV
135
    kw_wyd = dict(
×
136
        tytul=f"Tytul {kl} {c}",
137
        tytul_oryginalny=f"Tytul oryginalny {kl} {c}",
138
        uwagi=f"Uwagi {kl} {c}",
139
        szczegoly=f"Szczegóły {kl} {c}",
140
    )
141

UNCOV
142
    if klass == Patent:
×
143
        del kw_wyd["tytul"]
×
144

UNCOV
145
    for key, value in list(kw_wyd.items()):
×
UNCOV
146
        set_default(key, value, kw)
×
147

UNCOV
148
    Status_Korekty.objects.get_or_create(pk=1, nazwa="przed korektą")
×
149

UNCOV
150
    return baker.make(klass, rok=rok, **kw)
×
151

152

153
def any_ciagle(**kw):
2✔
154
    """
155
    :rtype: bpp.models.Wydawnictwo_Ciagle
156
    """
UNCOV
157
    if "zrodlo" not in kw:
×
158
        set_default("zrodlo", any_zrodlo(), kw)
×
UNCOV
159
    set_default("informacje", "zrodlo-informacje", kw)
×
UNCOV
160
    set_default("issn", "123-IS-SN-34", kw)
×
UNCOV
161
    return any_wydawnictwo(Wydawnictwo_Ciagle, **kw)
×
162

163

164
def any_zwarte_base(klass, **kw):
2✔
165
    if klass not in [Praca_Doktorska, Praca_Habilitacyjna, Patent]:
×
166
        set_default("liczba_znakow_wydawniczych", 31337, kw)
×
167

168
    set_default("informacje", "zrodlo-informacje dla zwarte", kw)
×
169

170
    if klass not in [Patent]:
×
171
        set_default("miejsce_i_rok", "Lublin %s" % CURRENT_YEAR, kw)
×
172
        set_default("wydawca_opis", "Wydawnictwo FOLIUM", kw)
×
173
        set_default("isbn", "123-IS-BN-34", kw)
×
174
        set_default("redakcja", "Redakcja", kw)
×
175

176
    return any_wydawnictwo(klass, **kw)
×
177

178

179
def any_zwarte(**kw):
2✔
180
    """
181
    :rtype: bpp.models.Wydawnictwo_Zwarte
182
    """
183
    return any_zwarte_base(Wydawnictwo_Zwarte, **kw)
×
184

185

186
def any_habilitacja(**kw):
2✔
187
    """
188
    :rtype: bpp.models.Praca_Habilitacyjna
189
    """
190
    if "jednostka" not in kw:
×
191
        kw["jednostka"] = any_jednostka()
×
192
    return any_zwarte_base(Praca_Habilitacyjna, **kw)
×
193

194

195
def any_doktorat(**kw):
2✔
196
    """
197
    :rtype: bpp.models.Praca_Habilitacyjna
198
    """
199
    if "jednostka" not in kw:
×
200
        kw["jednostka"] = any_jednostka()
×
201
    return any_zwarte_base(Praca_Doktorska, **kw)
×
202

203

204
def any_patent(**kw):
2✔
205
    """
206
    :rtype: bpp.models.Patent
207
    """
208
    return any_zwarte_base(Patent, **kw)
×
209

210

211
def any_zrodlo(**kw):
2✔
212
    """
213
    :rtype: bpp.models.Zrodlo
214
    """
UNCOV
215
    if "nazwa" not in kw:
×
216
        kw["nazwa"] = "Zrodlo %s" % time.time()
×
217

UNCOV
218
    if "skrot" not in kw:
×
UNCOV
219
        kw["skrot"] = "Zrod. %s" % time.time()
×
220

UNCOV
221
    return baker.make(Zrodlo, **kw)
×
222

223

224
def _lookup_fun(klass):
2✔
225
    def fun(skrot):
2✔
226
        return klass.objects.filter(skrot=skrot)
×
227

228
    return fun
2✔
229

230

231
typ_kbn = _lookup_fun(Typ_KBN)
2✔
232
jezyk = _lookup_fun(Jezyk)
2✔
233
charakter = _lookup_fun(Charakter_Formalny)
2✔
234

235

236
def scroll_into_view(browser, arg):
2✔
237
    warnings.warn("Uzyj show_element zamiast", DeprecationWarning, stacklevel=2)
1✔
238
    s = f"document.getElementById('{arg}').scrollIntoView(); window.scrollBy(0,-100);"
1✔
239
    return browser.execute_script(s)
1✔
240

241

242
def show_element(browser, element):
2✔
243
    s = """
2✔
244
        // console.log('enter---');
245
        window.scrollTo(0, 0);
246
        var viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
247
        // console.log(viewPortHeight);
248
        var elementTop = arguments[0].getBoundingClientRect().top;
249
        // console.log(elementTop);
250
        if (elementTop < (viewPortHeight/2)*0.5 || elementTop > (viewPortHeight/2)*1.5 ) {
251
            // console.log("scrolling");
252
            window.scrollTo(0, Math.max(0, elementTop-(viewPortHeight/2)));
253
            // console.log(Math.max(0, elementTop-(viewPortHeight/2)));
254
        }
255
        """
256
    return browser.execute_script(s, element._element)
2✔
257

258

259
def select_select2_autocomplete(
2✔
260
    browser, element_id, value, wait_for_new_value=True, value_before_enter=None
261
):
262
    """
263
    Wypełnia kontrolkę Select2
264

265
    :param browser: splinter.Browser
266
    :param element_id: ID elementu (tekst)
267
    :param value: tekst do wpisania
268
    """
269
    wait_for(lambda: len(browser.find_by_id(f"select2-{element_id}-container")) > 0)
2✔
270

271
    old_value = browser.find_by_id(f"select2-{element_id}-container").text
2✔
272

273
    # Znajdź interesujący nas select2-autocomplete
274
    element = browser.find_by_id(element_id)[0]
2✔
275
    sibling = element.find_by_xpath("following-sibling::span")
2✔
276

277
    if len(sibling) == 0:
2✔
278
        raise ElementDoesNotExist("sibling not found")
×
279

280
    sibling = sibling.first
2✔
281

282
    # Umieść go na widoku
283
    show_element(browser, sibling)
2✔
284

285
    # Kliknij w aktywny element, następnie wyślij klawisze do aktywnego
286
    # elementu, który się pojawił (wyskakujący pop-up select2)
287
    # następnie wyślij ENTER, następnie sprawdź, czy ustawiona została
288
    # nowa wartość. Jeżeli nie, to powtórz, maksimum 3 razy:
289

290
    # tries = 0
291
    # while True:
292

293
    sibling.click()
2✔
294

295
    # W tym momencie pojawi sie popup. Input type z klasą .select2-search__field
296
    # będzie jedyny na stronie:
297
    WebDriverWait(browser, SHORT_WAIT_TIME).until(
2✔
298
        lambda driver: driver.find_by_css(".select2-search__field")
299
    )
300

301
    input_box = element.parent.find_by_css(".select2-search__field")[0]
2✔
302

303
    list(input_box.type(value, slowly=True))
2✔
304

305
    wait_for(
2✔
306
        lambda: "Trwa wyszukiwanie…"
307
        not in browser.find_by_id(f"select2-{element_id}-results").value
308
    )
309

310
    input_box.type(Keys.ENTER)
2✔
311
    time.sleep(0.5)
2✔
312

313
    if wait_for_new_value:
2✔
314
        try:
1✔
315
            wait_for(
1✔
316
                lambda: browser.find_by_id(f"select2-{element_id}-container").text
317
                != old_value
318
            )
319
        except TimeoutError as e:
×
320
            raise e
×
321

322

323
def select_select2_clear_selection(browser, element_id):
2✔
UNCOV
324
    browser.find_by_id(element_id)[0]
×
UNCOV
325
    browser.execute_script(
×
326
        "django.jQuery('#" + element_id + "').val(null).trigger('change')"
327
    )
328

329

330
def select_element_by_text(browser, element_id, text):
2✔
331
    element = browser.find_by_id(element_id)
1✔
332
    show_element(browser, element)
1✔
333
    element.select_by_text(text)
1✔
334

335

336
def set_element(browser, element_id, text):
2✔
337
    element = browser.find_by_id(element_id)
1✔
338
    show_element(browser, element)
1✔
339
    element.type(text)
1✔
340

341

342
def submit_admin_form(browser):
2✔
343
    with wait_for_page_load(browser):
1✔
344
        browser.execute_script(
1✔
345
            'django.jQuery("input[type=submit].grp-default").click()'
346
        )
347

348

349
def proper_click_element(browser, element):
2✔
350
    # show_element(browser, element)
351
    # return element.click()
352
    browser.execute_script("arguments[0].scrollIntoView();", element._element)
2✔
353
    WebDriverWait(browser, SHORT_WAIT_TIME).until(visibility_of(element._element))
2✔
354
    browser.execute_script("arguments[0].click();", element._element)
2✔
355

356

357
def proper_click_by_id(browser, arg):
2✔
UNCOV
358
    elem = browser.find_by_id(arg)
×
UNCOV
359
    proper_click_element(browser, elem)
×
360

361

362
def assertPopupContains(browser, text, accept=True):
2✔
363
    """Switch to popup, assert it contains at least a part
364
    of the text, close the popup. Error otherwise.
365
    """
366
    alert = browser.driver.switch_to.alert
2✔
367
    if text not in alert.text:
2✔
368
        raise AssertionError(f"{text!r} not found in {alert.text!r}")
×
369
    if accept:
2✔
370
        alert.accept()
2✔
371

372

373
def add_extra_autor_inline(browser, no_current_inlines=0):
2✔
374
    elem = None
1✔
375

376
    WebDriverWait(browser, LONG_WAIT_TIME).until(
1✔
377
        lambda browser: not browser.find_by_css(".grp-add-handler").is_empty()
378
    )
379

380
    elems = browser.find_by_css(".grp-add-handler")
1✔
381

382
    for e in elems:
1✔
383
        if (
1✔
384
            e.visible
385
            and e.text.find("Dodaj") >= 0
386
            and e.text.find("powiązanie autora") >= 0
387
        ):
388
            elem = e
1✔
389
            break
1✔
390

391
    proper_click_element(browser, elem)
1✔
392

393
    try:
1✔
394
        wait_for(
1✔
395
            lambda: not browser.find_by_id(
396
                f"id_autorzy_set-{no_current_inlines}-autor"
397
            ).is_empty(),
398
            max_seconds=LONG_WAIT_TIME,
399
        )
400
    except TimeoutError as e:
×
401
        raise e
×
402

403

404
def randomobj(model):
2✔
405
    return model.objects.order_by("?").first()
1✔
406

407

408
def quick_find_by_id(browser, id):
2✔
409
    if f'id="{id}"' in browser.html:
1✔
410
        return browser.find_by_id(id, wait_time=0.01)
1✔
411

412

413
def fill_admin_form(
2✔
414
    browser,
415
    zrodlo=None,
416
    tytul_oryginalny="tytul oryginalny",
417
    jezyk=None,
418
    charakter_formalny=None,
419
    typ_kbn=None,
420
    status_korekty=None,
421
    rok=None,
422
):
423
    set_element(browser, "id_tytul_oryginalny", tytul_oryginalny)
1✔
424

425
    if quick_find_by_id(browser, "id_zrodlo"):
1✔
426
        if zrodlo is None:
1✔
427
            # from bpp.models import Zrodlo
428
            zrodlo = randomobj(Zrodlo)
1✔
429
        select_select2_autocomplete(browser, "id_zrodlo", zrodlo.nazwa)
1✔
430

431
    if quick_find_by_id(browser, "id_jezyk"):
1✔
432
        if jezyk is None:
1✔
433
            # from bpp.models import Jezk
434
            jezyk = randomobj(Jezyk)
1✔
435
        select_element_by_text(browser, "id_jezyk", jezyk.nazwa)
1✔
436

437
    if quick_find_by_id(browser, "id_charakter_formalny"):
1✔
438
        if charakter_formalny is None:
1✔
439
            # charakter_formalny = randomobj(Charakter_Formalny)
440
            charakter_formalny = Charakter_Formalny.objects.get(nazwa="Broszura")
1✔
441
        select_element_by_text(
1✔
442
            browser, "id_charakter_formalny", " " + charakter_formalny.nazwa
443
        )
444

445
    if quick_find_by_id(browser, "id_typ_kbn"):
1✔
446
        if typ_kbn is None:
1✔
447
            typ_kbn = randomobj(Typ_KBN)
1✔
448
        select_element_by_text(browser, "id_typ_kbn", typ_kbn.nazwa)
1✔
449

450
    if status_korekty is None:
1✔
451
        status_korekty = randomobj(Status_Korekty)
1✔
452
    select_element_by_text(browser, "id_status_korekty", "przed korektą")
1✔
453

454
    if rok is None:
1✔
455
        rok = random.randint(1, 2100)
1✔
456
    set_element(browser, "id_rok", rok)
1✔
457

458

459
def fill_admin_inline(
2✔
460
    browser,
461
    autor,
462
    jednostka,
463
    zapisany_jako=None,
464
    procent=None,
465
    no=0,
466
    prefix=None,
467
    dyscyplina=None,
468
):
469
    "Daj prefix równy 'id_' aby wypełniać pojedyncze formularze (nie inlines)"
470

471
    # Poza tymi wypełnianymi poniżej sa jeszcze:
472
    # autorzy_set-0-typ_odpowiedzialnosci
473
    # autorzy_set-0-afiliuje
474
    # autorzy_set-0-zatrudniony
475
    # autorzy_set-0-kolejnosc
476
    # autorzy_set-0-rekord
477
    # autorzy_set-0-id
478

479
    if prefix is None:
1✔
480
        prefix = f"id_autorzy_set-{no}-"
1✔
481

482
    select_select2_autocomplete(
1✔
483
        browser, f"{prefix}autor", f"{autor.nazwisko} {autor.imiona}"
484
    )
485
    select_select2_autocomplete(browser, f"{prefix}jednostka", jednostka.nazwa)
1✔
486
    if zapisany_jako is None:
1✔
487
        zapisany_jako = f"{autor.nazwisko} {autor.imiona}"
1✔
488
    select_select2_autocomplete(browser, f"{prefix}zapisany_jako", zapisany_jako)
1✔
489
    if procent is not None:
1✔
490
        set_element(browser, f"{prefix}procent", procent)
1✔
491
    if procent == -1:
1✔
492
        set_element(browser, f"{prefix}procent", str(random.randint(1, 100)) + ".00")
×
493

494
    if dyscyplina:
1✔
495
        # set_element(browser, f"{prefix}dyscyplina_naukowa", dyscyplina)
496
        select_select2_autocomplete(
×
497
            browser, f"{prefix}dyscyplina_naukowa", dyscyplina.nazwa
498
        )
499

500

501
def submitted_form_bad(browser, wait_time=SHORT_WAIT_TIME):
2✔
502
    WebDriverWait(browser.driver, wait_time).until(
1✔
503
        lambda driver: "Prosimy poprawić" in driver.page_source
504
    )
505
    return True
1✔
506

507

508
def submitted_form_good(browser, wait_time=SHORT_WAIT_TIME):
2✔
509
    WebDriverWait(browser.driver, wait_time).until(
1✔
510
        lambda driver: "został(a)(-ło) dodany(-na)(-ne) pomyślnie" in driver.page_source
511
    )
512
    return True
1✔
513

514

515
def browse_praca_url(model):
2✔
516
    return reverse(
×
517
        "bpp:browse_praca_by_slug", args=(model.slug,)
518
    )  # ContentType.objects.get_for_model(model).pk, model.pk)
519

520

521
def normalize_html(s: bytes | str, default_encoding="utf-8"):
2✔
522
    if isinstance(s, bytes):
1✔
523
        s = s.decode(default_encoding)
×
524
    s = s.replace("\r\n", " ").replace("\n", " ")
1✔
525
    return re.sub(r"\s\s+", " ", s)
1✔
526

527

528
def normalize_response_content(res: HttpResponse):
2✔
529
    return normalize_html(
×
530
        res.content, cgi.parse_header(res["content-type"])[1]["charset"]
531
    )
532

533

534
def rozwin_ekstra_informacje_na_stronie_edycji_wydawnictwa(admin_browser):
2✔
535
    for elem in admin_browser.find_by_tag("h2")[:3]:
1✔
536
        show_element(admin_browser, elem)  # ._element)
1✔
537
        elem.click()
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc