Skip to content
This repository was archived by the owner on Aug 10, 2022. It is now read-only.

Commit efc8c8d

Browse files
Merge pull request #31 from applitools/develop
Release 4.0.6
2 parents 7ac6ea4 + c78930c commit efc8c8d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+810
-315
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,4 @@ venv.bak/
193193
# mypy
194194
.mypy_cache/
195195
/eyes_selenium/node_modules/
196+
logs/

.travis.yml

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,65 @@
11
language: python
2-
addons:
3-
chrome: stable
4-
# firefox: latest
5-
matrix:
2+
install:
3+
- pip install -U tox
4+
before_script:
5+
# Run GUI apps in headless mode
6+
- export DISPLAY=:99.0
7+
- sh -e /etc/init.d/xvfb start
8+
- sleep 10 # give webdriver some time to start
9+
- export APPLITOOLS_BATCH_ID=`uuidgen -t`
10+
script:
11+
- echo $APPLITOOLS_BATCH_ID
12+
- tox -e $TOX_ENV
13+
stages:
14+
- lint
15+
- unit-tests
16+
- integration-tests
17+
- eyes-images-tests
18+
- functional-tests
19+
jobs:
620
include:
7-
- python: 2.7
21+
- stage: lint
22+
python: 3.6
823
env:
9-
- TOX_ENV=unit
10-
- python: 3.5
24+
- TOX_ENV=lint
25+
26+
- stage: unit-tests
27+
python: 2.7
1128
env:
1229
- TOX_ENV=unit
13-
- python: 2.7
14-
env:
15-
- TOX_ENV=images
16-
- python: 3.5
30+
- python: 3.6
1731
env:
18-
- TOX_ENV=images
19-
- python: 2.7
32+
- TOX_ENV=unit
33+
34+
- stage: integration-tests
35+
python: 2.7
2036
env:
2137
- TOX_ENV=integration
2238
- python: 3.6
2339
env:
2440
- TOX_ENV=integration
25-
- python: 2.7
41+
42+
- stage: functional-tests
43+
python: 3.6
44+
addons:
45+
chrome: stable
46+
firefox: latest
2647
env:
27-
- TOX_ENV=selenium
48+
- TOX_ENV=selenium-on-linux
2849
- python: 3.6
2950
env:
30-
- TOX_ENV=selenium
51+
- TOX_ENV=images
3152
- python: 3.6
53+
# env:
54+
# - TOX_ENV=selenium-on-windows-remote
55+
# - python: 3.6
56+
# env:
57+
# - TOX_ENV=selenium-on-macos-remote
58+
# - python: 3.6
3259
env:
33-
- TOX_ENV=selenium-appium
60+
- TOX_ENV=selenium-appium-remote
3461
- python: 3.6
62+
addons:
63+
chrome: stable
3564
env:
3665
- TOX_ENV=visualgrid
37-
- python: 3.6
38-
env:
39-
- TOX_ENV=lint
40-
install:
41-
- pip install -U tox
42-
before_script:
43-
- export DISPLAY=:99.0
44-
- sh -e /etc/init.d/xvfb start
45-
- sleep 10 # give webdriver some time to start
46-
- export APPLITOOLS_BATCH_ID=`uuidgen -t`
47-
script:
48-
- echo $APPLITOOLS_BATCH_ID
49-
- tox -e $TOX_ENV

eyes_common/applitools/common/config/configuration.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class BatchInfo(object):
2626
"""
2727

2828
name = attr.ib(
29-
factory=lambda: os.environ.get("APPLITOOLS_BATCH_NAME"),
29+
factory=lambda: os.getenv("APPLITOOLS_BATCH_NAME"),
3030
metadata={JsonInclude.THIS: True},
3131
) # type: Optional[Text]
3232
started_at = attr.ib(
@@ -35,12 +35,12 @@ class BatchInfo(object):
3535
) # type: Union[datetime, Text]
3636
sequence_name = attr.ib(
3737
init=False,
38-
factory=lambda: os.environ.get("APPLITOOLS_BATCH_SEQUENCE"),
38+
factory=lambda: os.getenv("APPLITOOLS_BATCH_SEQUENCE"),
3939
metadata={JsonInclude.NAME: "batchSequenceName"},
4040
) # type: Optional[Text]
4141
id = attr.ib(
4242
init=False,
43-
factory=lambda: os.environ.get("APPLITOOLS_BATCH_ID", str(uuid.uuid4())),
43+
factory=lambda: os.getenv("APPLITOOLS_BATCH_ID", str(uuid.uuid4())),
4444
metadata={JsonInclude.THIS: True},
4545
) # type: Text
4646

@@ -56,13 +56,13 @@ class Configuration(object):
5656

5757
batch = attr.ib(default=None) # type: Optional[BatchInfo]
5858
branch_name = attr.ib(
59-
factory=lambda: os.environ.get("APPLITOOLS_BRANCH", None)
59+
factory=lambda: os.getenv("APPLITOOLS_BRANCH", None)
6060
) # type: Optional[Text]
6161
parent_branch_name = attr.ib(
62-
factory=lambda: os.environ.get("APPLITOOLS_PARENT_BRANCH", None)
62+
factory=lambda: os.getenv("APPLITOOLS_PARENT_BRANCH", None)
6363
) # type: Optional[Text]
6464
baseline_branch_name = attr.ib(
65-
factory=lambda: os.environ.get("APPLITOOLS_BASELINE_BRANCH", None)
65+
factory=lambda: os.getenv("APPLITOOLS_BASELINE_BRANCH", None)
6666
) # type: Optional[Text]
6767
agent_id = attr.ib(default=None) # type: Optional[Text]
6868
baseline_env_name = attr.ib(default=None) # type: Optional[Text]
@@ -95,7 +95,7 @@ class Configuration(object):
9595
hide_caret = attr.ib(init=False, default=None)
9696
stitching_overlap = attr.ib(init=False, default=50)
9797

98-
api_key = attr.ib(factory=lambda: os.environ.get("APPLITOOLS_API_KEY", None))
98+
api_key = attr.ib(factory=lambda: os.getenv("APPLITOOLS_API_KEY", None))
9999
server_url = attr.ib(default=DEFAULT_SERVER_URL)
100100
timeout = attr.ib(default=DEFAULT_TIMEOUT_MS) # ms
101101

eyes_common/applitools/common/logger.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
_DEFAULT_EYES_FORMATTER = logging.Formatter(
1616
"%(asctime)s [%(levelname)s] %(threadName)-9s) %(name)s: %(message)s"
1717
)
18-
_DEFAULT_LOGGER_LEVEL = int(os.environ.get("LOGGER_LEVEL", logging.INFO))
19-
_DEBUG_SCREENSHOT_PREFIX = os.environ.get("DEBUG_SCREENSHOT_PREFIX", "screenshot_")
20-
_DEBUG_SCREENSHOT_PATH = os.environ.get("DEBUG_SCREENSHOT_PATH", ".")
18+
_DEFAULT_LOGGER_LEVEL = int(os.getenv("LOGGER_LEVEL", logging.INFO))
19+
_DEBUG_SCREENSHOT_PREFIX = os.getenv("DEBUG_SCREENSHOT_PREFIX", "screenshot_")
20+
_DEBUG_SCREENSHOT_PATH = os.getenv("DEBUG_SCREENSHOT_PATH", ".")
2121

2222
__all__ = ("StdoutLogger", "FileLogger", "NullLogger")
2323

eyes_common/applitools/common/visual_grid.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class RenderStatus(Enum):
4141
RENDERED = "rendered"
4242
ERROR = "error"
4343
NEED_MORE_DOM = "need-more-dom"
44+
INTERNAL_FAILURE = "internal failure"
4445

4546

4647
@attr.s(frozen=True)

eyes_core/applitools/core/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
NullRegionProvider,
2424
PositionProvider,
2525
RegionProvider,
26+
PositionMomento,
2627
)
2728
from .scaling import (
2829
ContextBasedScaleProvider,
@@ -43,8 +44,12 @@
4344
"ScaleProvider",
4445
"EyesBase",
4546
"PositionProvider",
47+
"PositionMomento",
4648
"InvalidPositionProvider",
4749
"RegionProvider",
50+
"FixedCutProvider",
51+
"NullCutProvider",
52+
"UnscaledFixedCutProvider",
4853
"NullRegionProvider",
4954
"NULL_REGION_PROVIDER",
5055
"CheckSettings",

eyes_core/applitools/core/debug.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
class DebugScreenshotProvider(object):
1212
"""Interface for saving debug screenshots."""
1313

14-
DEFAULT_PREFIX = os.environ.get("DEBUG_SCREENSHOT_PREFIX", "screenshot_")
15-
DEFAULT_PATH = os.environ.get("DEBUG_SCREENSHOT_PATH", "")
14+
DEFAULT_PREFIX = os.getenv("DEBUG_SCREENSHOT_PREFIX", "screenshot_")
15+
DEFAULT_PATH = os.getenv("DEBUG_SCREENSHOT_PATH", "")
1616

1717
_prefix = attr.ib(default=DEFAULT_PREFIX)
1818
_path = attr.ib(default=DEFAULT_PATH)

eyes_core/applitools/core/eyes_base.py

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
from applitools.common.utils import ABC, argument_guard, general_utils
2626
from applitools.common.visual_grid import RenderingInfo
2727
from applitools.core.capture import AppOutputProvider, AppOutputWithScreenshot
28-
from applitools.core.cut import NullCutProvider
28+
from applitools.core.cut import (
29+
NullCutProvider,
30+
FixedCutProvider,
31+
UnscaledFixedCutProvider,
32+
)
2933
from applitools.core.debug import (
3034
FileDebugScreenshotProvider,
3135
NullDebugScreenshotProvider,
@@ -40,7 +44,7 @@
4044
from applitools.common.utils.custom_types import ViewPort, UserInputs, Num
4145
from applitools.core.fluent.check_settings import CheckSettings
4246
from applitools.common.capture import EyesScreenshot
43-
from typing import Optional, Text
47+
from typing import Optional, Text, Union
4448

4549
__all__ = ("EyesBase",)
4650

@@ -172,8 +176,17 @@ def debug_screenshot_provider(self):
172176

173177
@property
174178
def cut_provider(self):
179+
# type: () -> Union[FixedCutProvider, UnscaledFixedCutProvider, NullCutProvider]
175180
return self._cut_provider
176181

182+
@cut_provider.setter
183+
def cut_provider(self, provider):
184+
# type: (Union[FixedCutProvider, UnscaledFixedCutProvider, NullCutProvider]) -> None
185+
argument_guard.is_in(
186+
provider, [FixedCutProvider, UnscaledFixedCutProvider, NullCutProvider]
187+
)
188+
self._cut_provider = provider
189+
177190
@property
178191
def is_debug_screenshot_provided(self):
179192
# type: () -> bool
@@ -182,6 +195,7 @@ def is_debug_screenshot_provided(self):
182195

183196
@is_debug_screenshot_provided.setter
184197
def is_debug_screenshot_provided(self, save):
198+
# type: (bool) -> None
185199
prev = self._debug_screenshot_provider
186200
if save:
187201
self._debug_screenshot_provider = FileDebugScreenshotProvider(
@@ -293,7 +307,7 @@ def close(self, raise_ex=True):
293307
try:
294308
logger.debug("close({})".format(raise_ex))
295309
if not self._is_opened:
296-
raise ValueError("Eyes not open")
310+
raise EyesError("Eyes not open")
297311

298312
self._is_opened = False
299313

@@ -325,7 +339,7 @@ def close(self, raise_ex=True):
325339
if results.is_new:
326340
instructions = "Please approve the new baseline at " + results_url
327341
logger.info("--- New test ended. " + instructions)
328-
if raise_ex:
342+
if raise_ex or self.configuration.fail_on_new_test:
329343
message = "'%s' of '%s'. %s" % (
330344
self._session_start_info.scenario_id_or_name,
331345
self._session_start_info.app_id_or_name,
@@ -369,19 +383,19 @@ def close(self, raise_ex=True):
369383
self._running_session = None
370384
logger.close()
371385

372-
def abort_if_not_closed(self):
386+
def abort(self):
373387
# type: () -> None
374388
"""
375389
If a test is running, aborts it. Otherwise, does nothing.
376390
"""
377391
if self.configuration.is_disabled:
378-
logger.debug("abort_if_not_closed(): ignored (disabled)")
392+
logger.debug("abort(): ignored (disabled)")
379393
return
380394
try:
381395
self._reset_last_screenshot()
382396

383397
if self._running_session:
384-
logger.debug("abort_if_not_closed(): Aborting session...")
398+
logger.debug("abort(): Aborting session...")
385399
try:
386400
self._server_connector.stop_session(
387401
self._running_session, True, False
@@ -395,6 +409,10 @@ def abort_if_not_closed(self):
395409
finally:
396410
logger.close()
397411

412+
def abort_if_not_closed(self):
413+
logger.deprecation("Use `abort()` instead")
414+
self.abort()
415+
398416
def open_base(
399417
self,
400418
app_name, # type: Text
@@ -474,7 +492,6 @@ def _open_base(self):
474492
retry = 0
475493
while retry < self.MAX_ITERATION:
476494
try:
477-
self._validate_api_key()
478495
self._validate_session_open()
479496
self._init_providers()
480497

@@ -501,7 +518,7 @@ def _open_base(self):
501518

502519
def _validate_session_open(self):
503520
if self.is_opened:
504-
self.abort_if_not_closed()
521+
self.abort()
505522
raise EyesError("A test is already running")
506523

507524
def _log_open_base(self):
@@ -519,13 +536,6 @@ def _log_open_base(self):
519536
"FailureReports = '{}' ".format(self.configuration.failure_reports)
520537
)
521538

522-
def _validate_api_key(self):
523-
if self.configuration.api_key is None:
524-
raise EyesError(
525-
"API key not set! Log in to https://applitools.com to obtain your"
526-
" API Key and use 'api_key' to set it."
527-
)
528-
529539
def _create_session_start_info(self):
530540
# type: () -> None
531541
self._session_start_info = SessionStartInfo(

eyes_core/applitools/core/positioning/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
from .position_provider import InvalidPositionProvider, PositionProvider # noqa: F401
1+
from .position_provider import (
2+
InvalidPositionProvider,
3+
PositionProvider,
4+
PositionMomento,
5+
) # noqa: F401
26
from .region_provider import ( # noqa: F401
37
NULL_REGION_PROVIDER,
48
NullRegionProvider,

eyes_core/applitools/core/positioning/position_provider.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,32 @@
44
import attr
55

66
from applitools.common.geometry import Point
7-
from applitools.common.utils import ABC
7+
from applitools.common.utils import ABC, iteritems
88

99
if typing.TYPE_CHECKING:
1010
from typing import List, Optional
1111
from applitools.common import RectangleSize
1212

1313

14+
class PositionMomento(object):
15+
"""
16+
A base class for position related memento instances. This is intentionally
17+
not an interface, since the mementos might vary in their interfaces.
18+
"""
19+
20+
def __init__(self, position, **kwargs):
21+
self.position = position
22+
for name, val in iteritems(kwargs):
23+
setattr(self, name, val)
24+
25+
def __str__(self):
26+
return "PositionMomento(position={}, ...)".format(self.position)
27+
28+
1429
@attr.s
1530
class PositionProvider(ABC):
16-
_states = attr.ib(init=False, factory=list) # type: List[Point]
31+
_states = attr.ib(init=False, factory=list) # type: List[PositionMomento]
32+
_last_set_position = attr.ib(init=False, default=None) # type: Point
1733

1834
@abc.abstractmethod
1935
def get_current_position(self):
@@ -42,16 +58,15 @@ def push_state(self):
4258
"""
4359
Adds the current position to the states list.
4460
"""
45-
self._states.append(self.get_current_position())
61+
self._states.append(PositionMomento(self.get_current_position()))
4662

4763
def pop_state(self):
48-
# type: ()-> Point
4964
"""
5065
Sets the position to be the last position added to the states list.
5166
"""
5267
state = self._states.pop()
53-
self.set_position(state)
54-
return state
68+
self.set_position(state.position)
69+
self._last_set_position = state.position
5570

5671
@property
5772
def states(self):

0 commit comments

Comments
 (0)