100% found this document useful (3 votes)
120 views

Selenium WebDriver Recipes in Python The problem solving guide to Selenium WebDriver in Python 1st Edition Zhimin Zhan pdf download

The document is a promotional listing for various eBooks, including 'Selenium WebDriver Recipes in Python' by Zhimin Zhan, which serves as a problem-solving guide for using Selenium WebDriver with Python. It provides links to purchase and download multiple related titles covering topics such as web test automation, algorithms, online payment security, and more. The document emphasizes the availability of instant digital products in various formats.

Uploaded by

nuzzobrumla
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (3 votes)
120 views

Selenium WebDriver Recipes in Python The problem solving guide to Selenium WebDriver in Python 1st Edition Zhimin Zhan pdf download

The document is a promotional listing for various eBooks, including 'Selenium WebDriver Recipes in Python' by Zhimin Zhan, which serves as a problem-solving guide for using Selenium WebDriver with Python. It provides links to purchase and download multiple related titles covering topics such as web test automation, algorithms, online payment security, and more. The document emphasizes the availability of instant digital products in various formats.

Uploaded by

nuzzobrumla
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 51

Selenium WebDriver Recipes in Python The problem

solving guide to Selenium WebDriver in Python


1st Edition Zhimin Zhan pdf download

https://ebookname.com/product/selenium-webdriver-recipes-in-
python-the-problem-solving-guide-to-selenium-webdriver-in-
python-1st-edition-zhimin-zhan/

Get Instant Ebook Downloads – Browse at https://ebookname.com


Instant digital products (PDF, ePub, MOBI) available
Download now and explore formats that suit you...

Selenium design patterns and best practices build a


powerful stable and automated test suite using Selenium
WebDriver Kovalenko

https://ebookname.com/product/selenium-design-patterns-and-best-
practices-build-a-powerful-stable-and-automated-test-suite-using-
selenium-webdriver-kovalenko/

Problem Solving with Algorithms and Data Structures


Using Python SECOND EDITION Bradley N. Miller

https://ebookname.com/product/problem-solving-with-algorithms-
and-data-structures-using-python-second-edition-bradley-n-miller/

Programming in Python 3 A Complete Introduction to the


Python Language 2nd Edition Summerfield

https://ebookname.com/product/programming-in-python-3-a-complete-
introduction-to-the-python-language-2nd-edition-summerfield/

Essentials of Online payment Security and Fraud


Prevention Essentials Series 1st Edition David A.
Montague

https://ebookname.com/product/essentials-of-online-payment-
security-and-fraud-prevention-essentials-series-1st-edition-
david-a-montague/
Recessions Prospects and Developments Prospects and
Developments 1st Edition Nerea M. Pérez

https://ebookname.com/product/recessions-prospects-and-
developments-prospects-and-developments-1st-edition-nerea-m-
perez/

The Last Sorcerers The Path From Alchemy To The


Periodic Table 1st Edition Morris Richard

https://ebookname.com/product/the-last-sorcerers-the-path-from-
alchemy-to-the-periodic-table-1st-edition-morris-richard/

Essentials of Stem Cell Biology 1st Edition R Lanza

https://ebookname.com/product/essentials-of-stem-cell-
biology-1st-edition-r-lanza/

Nanomedicine and the Cardiovascular System 1st Edition


Ross J. Hunter (Editor)

https://ebookname.com/product/nanomedicine-and-the-
cardiovascular-system-1st-edition-ross-j-hunter-editor/

The New Physics for the Twenty First Century 2Rev Ed


Edition Gordon Fraser

https://ebookname.com/product/the-new-physics-for-the-twenty-
first-century-2rev-ed-edition-gordon-fraser/
Microtexture Determination and Its Applications 2nd
Edition Valerie Randle

https://ebookname.com/product/microtexture-determination-and-its-
applications-2nd-edition-valerie-randle/
Selenium WebDriver Recipes in Python
The problem solving guide to Selenium WebDriver in
Python

Zhimin Zhan
This book is for sale at http://leanpub.com/selenium-recipes-in-python

This version was published on 2020-06-12

This is a Leanpub book. Leanpub empowers authors and publishers with the Lean
Publishing process. Lean Publishing is the act of publishing an in-progress ebook using
lightweight tools and many iterations to get reader feedback, pivot until you have the right
book and build traction once you do.

© 2015 - 2020 Zhimin Zhan


Also By Zhimin Zhan
Practical Web Test Automation
Watir Recipes
Selenium WebDriver Recipes in Ruby
Selenium WebDriver Recipes in Java
Learn Ruby Programming by Examples
Learn Swift Programming by Examples
API Testing Recipes in Ruby
Selenium WebDriver Recipes in Node.js
Contents

Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i
Who should read this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii
How to read this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii
Recipe test scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii
Send me feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii

1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Selenium language bindings . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Install Selenium Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Cross browser testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 unittest - Python Unit Testing Framework . . . . . . . . . . . . . . . . . . . 8
1.5 Run recipe scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2. Locating web elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14


2.1 Start browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 Find element by ID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3 Find element by Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4 Find element by Link Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.5 Find element by Partial Link Text . . . . . . . . . . . . . . . . . . . . . . . . 16
2.6 Find element by XPath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.7 Find element by Tag Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.8 Find element by Class Name . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.9 Find element by CSS Selector . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.10 Chain find_element to find child elements . . . . . . . . . . . . . . . . . . . 18
2.11 Find multiple elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3. Hyperlink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1 Start browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2 Click a link by text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
CONTENTS

3.3 Click a link by ID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21


3.4 Click a link by partial text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.5 Click a link by XPath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.6 Click Nth link with exact same label . . . . . . . . . . . . . . . . . . . . . . . 22
3.7 Click Nth link by CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.8 Verify a link present or not? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.9 Getting link data attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.10 Test links open a new browser window . . . . . . . . . . . . . . . . . . . . . 24

4. Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.1 Click a button by text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.2 Click a form button by text . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.3 Submit a form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.4 Click a button by ID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.5 Click a button by name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.6 Click a image button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.7 Click a button via JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.8 Assert a button present . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.9 Assert a button enabled or disabled? . . . . . . . . . . . . . . . . . . . . . . . 28

5. TextField and TextArea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29


5.1 Enter text into a text field by name . . . . . . . . . . . . . . . . . . . . . . . 29
5.2 Enter text into a text field by ID . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.3 Enter text into a password field . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.4 Clear a text field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.5 Enter text into a multi-line text area . . . . . . . . . . . . . . . . . . . . . . . 30
5.6 Assert value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.7 Focus on a control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.8 Set a value to a read-only or disabled text field . . . . . . . . . . . . . . . . . 31
5.9 Set and assert the value of a hidden field . . . . . . . . . . . . . . . . . . . . 31

6. Radio button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.1 Select a radio button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.2 Clear radio option selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.3 Assert a radio option is selected . . . . . . . . . . . . . . . . . . . . . . . . . 34
6.4 Iterate radio buttons in a radio group . . . . . . . . . . . . . . . . . . . . . . 34
6.5 Click Nth radio button in a group . . . . . . . . . . . . . . . . . . . . . . . . 34
6.6 Click radio button by the following label . . . . . . . . . . . . . . . . . . . . 35
6.7 Customized Radio buttons - iCheck . . . . . . . . . . . . . . . . . . . . . . . 36
CONTENTS

7. CheckBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
7.1 Select by name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
7.2 Uncheck a checkbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
7.3 Assert a checkbox is checked (or not) . . . . . . . . . . . . . . . . . . . . . . 37
7.4 Customized Checkboxes - iCheck . . . . . . . . . . . . . . . . . . . . . . . . 38

8. Select List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
8.1 Select an option by text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
8.2 Select an option by value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
8.3 Select an option by index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
8.4 Select an option by iterating all options . . . . . . . . . . . . . . . . . . . . . 40
8.5 Select multiple options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
8.6 Clear one selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
8.7 Clear all selections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
8.8 Assert label or value in a select list . . . . . . . . . . . . . . . . . . . . . . . . 41
8.9 Assert selected option label . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
8.10 Assert the value of a select list . . . . . . . . . . . . . . . . . . . . . . . . . . 41
8.11 Assert multiple selections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

9. Navigation and Browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43


9.1 Go to a URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
9.2 Visit pages within a site . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
9.3 Perform actions from right mouse click context menu such as ‘Back’,
‘Forward’ or ‘Refresh’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
9.4 Open browser in certain size . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
9.5 Maximize browser window . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
9.6 Move browser window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
9.7 Minimize browser window . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
9.8 Scroll focus to control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
9.9 Switch between browser windows or tabs . . . . . . . . . . . . . . . . . . . 45
9.10 Open new and close browser Tabs . . . . . . . . . . . . . . . . . . . . . . . . 46
9.11 Remember current web page URL, then come back to it later . . . . . . . . 47

10. Assertion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
10.1 Assert page title . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
10.2 Assert Page Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
10.3 Assert Page Source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
10.4 Assert Label Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
10.5 Assert Span text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
CONTENTS

10.6 Assert Div text or HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49


10.7 Assert Table text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
10.8 Assert text in a table cell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
10.9 Assert text in a table row . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
10.10 Assert image present . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
10.11 Assert element location and width . . . . . . . . . . . . . . . . . . . . . . . . 52
10.12 Assert element CSS style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
10.13 Assert JavaScript errors on a web page . . . . . . . . . . . . . . . . . . . . . 52

11. Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
11.1 Testing Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
11.2 Testing IFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
11.3 Test multiple iframes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

12. Testing AJAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56


12.1 Wait within a time frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.2 Explicit Waits until Time out . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.3 Implicit Waits until Time out . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.4 Create your own polling check function . . . . . . . . . . . . . . . . . . . . . 58
12.5 Wait AJAX Call to complete using JQuery . . . . . . . . . . . . . . . . . . . 58

13. File Upload and Popup dialogs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60


13.1 File upload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
13.2 JavaScript pop ups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
13.3 Modal style dialogs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
13.4 Bypass basic authentication by embedding username and password in URL 63
13.5 Internet Explorer modal dialog . . . . . . . . . . . . . . . . . . . . . . . . . . 63
13.6 Popup Handler Approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
13.7 Handle JavaScript dialog with Popup Handler . . . . . . . . . . . . . . . . . 65
13.8 Basic or Proxy Authentication Dialog . . . . . . . . . . . . . . . . . . . . . . 66

14. Debugging Test Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67


14.1 Print text for debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
14.2 Write page source or element HTML into a file . . . . . . . . . . . . . . . . 67
14.3 Take screenshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
14.4 Leave browser open after test finishes . . . . . . . . . . . . . . . . . . . . . . 68
14.5 Debug test execution using Debugger . . . . . . . . . . . . . . . . . . . . . . 69
14.6 Attach test executions to an existing browser . . . . . . . . . . . . . . . . . . 71
CONTENTS

15. Test Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73


15.1 Get date dynamically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
15.2 Get a random boolean value . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
15.3 Generate a number within a range . . . . . . . . . . . . . . . . . . . . . . . . 74
15.4 Get a random character . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
15.5 Get a random string at fixed length . . . . . . . . . . . . . . . . . . . . . . . 75
15.6 Get a random string in a collection . . . . . . . . . . . . . . . . . . . . . . . 75
15.7 Generate random person names, emails, addresses with Faker . . . . . . . . 75
15.8 Generate a test file at fixed sizes . . . . . . . . . . . . . . . . . . . . . . . . . 76
15.9 Retrieve data from Database . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

16. Browser Profile and Capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78


16.1 Get browser type and version . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
16.2 Set HTTP Proxy for Browser . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
16.3 Verify file download in Chrome . . . . . . . . . . . . . . . . . . . . . . . . . 79
16.4 Test downloading PDF in Firefox . . . . . . . . . . . . . . . . . . . . . . . . . 79
16.5 Bypass basic authentication with Firefox AutoAuth plugin . . . . . . . . . . 80
16.6 Manage Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
16.7 Headless browser testing with PhantomJS . . . . . . . . . . . . . . . . . . . 83
16.8 Headless Chrome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
16.9 Headless Firefox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
16.10 Test responsive websites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
16.11 Set page load timeout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
16.12 Device emulation on Chrome . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

17. Advanced User Interactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87


17.1 Double click a control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
17.2 Move mouse to a control - Mouse Over . . . . . . . . . . . . . . . . . . . . . 88
17.3 Click and hold - select multiple items . . . . . . . . . . . . . . . . . . . . . . 88
17.4 Context Click - right click a control . . . . . . . . . . . . . . . . . . . . . . . 88
17.5 Drag and drop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
17.6 Drag slider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
17.7 Send key sequences - Select All and Delete . . . . . . . . . . . . . . . . . . . 90
17.8 Click a specific part of an image . . . . . . . . . . . . . . . . . . . . . . . . . 91

18. HTML 5 and Dynamic Web Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93


18.1 HTML5 Email type field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
18.2 HTML5 Time Field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
18.3 Invoke ‘onclick’ JavaScript event . . . . . . . . . . . . . . . . . . . . . . . . . 94
CONTENTS

18.4 Invoke JavaScript events such as ‘onchange’ . . . . . . . . . . . . . . . . . . 95


18.5 Scroll to the bottom of a page . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
18.6 Select2 - Single Select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
18.7 Select2 - Multiple Select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
18.8 AngularJS web pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
18.9 Ember JS web pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
18.10 “Share Location” with Firefox . . . . . . . . . . . . . . . . . . . . . . . . . . 104
18.11 Faking Geolocation with JavaScript . . . . . . . . . . . . . . . . . . . . . . . 105
18.12 Save a canvas to PNG image . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
18.13 Verify dynamic charts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

19. WYSIWYG HTML editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107


19.1 TinyMCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
19.2 CKEditor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
19.3 SummerNote . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
19.4 CodeMirror . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

20. Leverage Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111


20.1 Raise exceptions to fail test . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
20.2 Ignorable test statement error . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
20.3 Read external file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
20.4 Data-Driven Tests with Excel . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
20.5 Data-Driven Tests with CSV . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
20.6 Identify element IDs with dynamically generated long prefixes . . . . . . . 115
20.7 Sending special keys such as Enter to an element or browser . . . . . . . . . 116
20.8 Use of unicode in test scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
20.9 Extract a group of dynamic data : verify search results in order . . . . . . . 116
20.10 Verify uniqueness of a set of data . . . . . . . . . . . . . . . . . . . . . . . . 117
20.11 Extract dynamic visible data rows from a results table . . . . . . . . . . . . 118
20.12 Extract dynamic text following a pattern using Regex . . . . . . . . . . . . . 120
20.13 Quick extract pattern text in comments with Regex . . . . . . . . . . . . . . 121

21. Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123


21.1 Assert page_source is faster than page text . . . . . . . . . . . . . . . . . . . 123
21.2 Getting text from specific element is faster . . . . . . . . . . . . . . . . . . . 124
21.3 Avoid programming if-else block if possible . . . . . . . . . . . . . . . . . . 124
21.4 Use variable to cache not-changed data . . . . . . . . . . . . . . . . . . . . . 124
21.5 Enter large text into a text box . . . . . . . . . . . . . . . . . . . . . . . . . . 125
21.6 Use Environment Variables to change test behaviours dynamically . . . . . 126
CONTENTS

21.7 Test web site in two languages . . . . . . . . . . . . . . . . . . . . . . . . . . 127


21.8 Multi-language testing with lookups . . . . . . . . . . . . . . . . . . . . . . . 128

22. Gotchas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131


22.1 Test starts browser but no execution with blank screen . . . . . . . . . . . . 131
22.2 Failed to assert copied text in browser . . . . . . . . . . . . . . . . . . . . . . 132
22.3 The same test works for Chrome, but not IE . . . . . . . . . . . . . . . . . . 133
22.4 “unexpected tag name ‘input’” . . . . . . . . . . . . . . . . . . . . . . . . . . 134
22.5 Element is not clickable or not visible . . . . . . . . . . . . . . . . . . . . . . 134

23. Material Design Web App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136


23.1 Select List (dropdown) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
23.2 Checkbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
23.3 Drag range (noUiSlider) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
23.4 Verify Toast message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
23.5 Modal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

24. Selenium Remote Control Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139


24.1 Selenium Server Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
24.2 Execute tests in specified browser on another machine . . . . . . . . . . . . 140
24.3 Selenium Grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

Appendix - Continuous Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145


Verify server machine can run Selenium Python . . . . . . . . . . . . . . . . . . . . 145
Install BuildWise Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Create Build Project in BuildWise . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Trigger test execution manually . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Feedback while test execution in progress . . . . . . . . . . . . . . . . . . . . . . . . 149
Build finished . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152

Afterword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153

Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Web Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Preface
After observing many failed test automation attempts by using expensive commercial test
automation tools, I am delighted to see that the value of open-source testing frameworks has
finally been recognized. I still remember the day (a rainy day at a Gold Coast hotel in 2011)
when I found out that the Selenium WebDriver was the most wanted testing skill in terms
of the number of job ads on the Australia’s top job-seeking site.
Now Selenium WebDriver is big in the testing world. We all know software giants such
as Facebook and LinkedIn use it, immensely-comprehensive automated UI testing enables
them pushing out releases several times a day¹. However, from my observation, many
software projects, while using Selenium, are not getting much value from test automation,
and certainly nowhere near its potential. A clear sign of this is that the regression testing is
not conducted on a daily basis (if test automation is done well, it will happen naturally).
Among the factors contributing to test automation failures, a key one is that automation
testers lack sufficient knowledge in the test framework. It is quite common to see some
testers or developers get excited when they first create a few simple test cases and see them
run in a browser. However, it doesn’t take long for them to encounter some obstacles: such as
being unable to automate certain operations. If one step cannot be automated, the whole test
case does not work, which is the nature of test automation. Searching solutions online is not
always successful, and posting questions on forums and waiting can be frustrating (usually,
very few people seek professional help from test automation coaches). Not surprisingly,
many projects eventually gave up test automation or just used it for testing a handful of
scenarios.
The motivation of this book is to help motivated testers work better with Selenium. The book
contains over 190 recipes for web application tests with Selenium. If you have read one of
my other books: Practical Web Test Automation², you probably know my style: practical. I
will let the test scripts do most of the talking. These recipe test scripts are ‘live’, as I have
created the target test site and included offline test web pages. With both, you can:

1. Identify your issue


2. Find the recipe
¹http://www.wired.com/business/2013/04/linkedin-software-revolution/
²https://leanpub.com/practical-web-test-automation
Preface ii

3. Run the test case


4. See test execution in your browser

Who should read this book


This book is for testers or programmers who are writing (or want to learn) automated tests
with Selenium WebDriver. In order to get the most of this book, basic Ruby coding skill is
required.

How to read this book

Usually, a ‘recipe’ book is a reference book. Readers can go directly to the part that interests
them. For example, if you are testing a multiple select list and don’t know how, you can look
up in the Table of Contents, then go to the chapter 8. This book supports this style of reading.
If you are new to Selenium WebDriver, I recommend you to try out the recipes from the
front to back. The recipes in the first half of the book are arranged according to their levels of
complexity, I believe readers can get the pattern of testing with Selenium and gain confidence
after going through them.

Recipe test scripts


To help readers to learn more effectively, this book has a dedicated site³ that contains the
recipe test scripts, test web pages and related resources. For access code, please see the
Resources section of this book.
As an old saying goes, “There’s more than one way to skin a cat.” You can achieve the same
testing outcome with test scripts implemented in different ways. The recipe test scripts in
this book are written for simplicity, and there is always room for improvement. But for many,
to understand the solution quickly and get the job done are probably more important.
If you have a better and simpler way, please let me know.
All recipe test scripts are Selenium WebDriver 3 compliant, and can be run against Chrome,
Firefox and Internet Explorer on multiple platforms. I plan to keep the test scripts updated
with the latest stable Selenium version.
³http://zhimin.com/books/selenium-recipes-nodejs
Preface iii

Send me feedback
I would appreciate your comments, suggestions, reports on errors in the book and the recipe
test scripts. You may submit your feedback on the book’s site.

Zhimin Zhan
Brisbane, Australia
1. Introduction
Selenium is a free and open source library for automated testing web applications. Selenium
was originally created in 2004 by Jason Huggins, it merged with another test framework
WebDriver in 2011 (that’s why is named ‘selenium-webdriver’) led by Simon Stewart at
Google (update: Simon now works at FaceBook). As WebDriver is a W3C standard¹, it gains
support from all major browser vendors, as a result, Selenium WebDriver quickly become
the de facto framework for automated testing web applications.

1.1 Selenium language bindings


Selenium tests can be written in multiple programming languages such as Java, C#, Python,
JavaScript and Ruby (the core ones). Quite commonly, I heard the saying such as “This is a
Java project, so we shall write tests in Java as well”. I disagree. Software testing is to verify
whether programmer’s work meets customer’s needs. In a sense, testers are representing
customers. Testers should have more weight on deciding the test syntax than programmers.
Plus, why would you mandate that your testers should have the same programming language
skills as the programmers. In my subjective view, scripting languages such as Ruby and
Python are more suitable for test scripts than compiled languages such as C# and Java
(Confession: I have been programming in Java for over 10 years). By the way, we call them
test scripts, for a reason.
All examples in this book are written in Selenium with Python binding. This does not mean
this book is limited to testers/developers who know Python. As you will see the examples
below, the use of Selenium in different bindings are very similar. Once you master one, you
can apply it to others quite easily. Take a look at a simple Selenium test script in five different
language bindings: Java, C#, JavaScript, Ruby and Python.
Java:

¹https://www.w3.org/TR/webdriver/
Introduction 2

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class GoogleSearch {


public static void main(String[] args) {
// Create a new instance of the html unit driver
// Notice that the remainder of the code relies on the interface,
// not the implementation.
WebDriver driver = new FirefoxDriver();

// And now use this to visit Google


driver.get("http://www.google.com");

// Find the text input element by its name


WebElement element = driver.findElement(By.name("q"));

// Enter something to search for


element.sendKeys("Hello Selenium WebDriver!");

// Submit the form based on an element in the form


element.submit();

// Check the title of the page


System.out.println("Page title is: " + driver.getTitle());
}
}

C#:

using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;

class GoogleSearch
{
static void Main()
{
IWebDriver driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://www.google.com");
IWebElement query = driver.FindElement(By.Name("q"));
query.SendKeys("Hello Selenium WebDriver!");
Introduction 3

query.Submit();
Console.WriteLine(driver.Title);
}
}

JavaScript:

var webdriver = require('selenium-webdriver');


var driver = new webdriver.Builder()
.forBrowser('chrome')
.build();

driver.get('http://www.google.com/ncr');
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.name('btnG')).click();
driver.wait(webdriver.until.titleIs('webdriver - Google Search'), 1000);
console.log(driver.title);

Ruby:

require "selenium-webdriver"

driver = Selenium::WebDriver.for :firefox


driver.navigate.to "http://www.google.com"

element = driver.find_element(:name, 'q')


element.send_keys "Hello Selenium WebDriver!"
element.submit

puts driver.title

Python:

from selenium import webdriver

driver = webdriver.Firefox()
driver.get("http://www.google.com")

elem = driver.find_element_by_name("q")
elem.send_keys("Hello WebDriver!")
elem.submit()

print(driver.title)
Introduction 4

1.2 Install Selenium Python


1. Download and install Python.
Python 2 is pre-installed on Mac and most Linux distributions. For new Python
projects, I would recommend Python 3, which was first released in 2008. Here are
the instructions to install Python on Windows.
Download latest installer² and run the installer.

Accept all default options except “Add python.exe to Path” for convenience.
For Mac,
brew install python3

2. Install Selenium-WebDriver for Python.


PIP is the package manager for Python. PIP comes with Python installer, run the
command below to upgrade to the latest PIP version.
> python -m pip install --upgrade pip

Install Selenium-WebDriver for Python.

²https://www.python.org/downloads
Introduction 5

C:\Users\Administrator>pip3 install selenium


Collecting selenium
Downloading selenium-3.141.0-py2.py3-none-any.whl (904kB)
100% |################################| 911kB 525kB/s
Installing collected packages: selenium
Collecting urllib3 (from selenium)
Downloading urllib3-1.24-py2.py3-none-any.whl (117kB)
Successfully installed selenium-3.141.0 urllib3-1.24

3. Your target browses are installed, such as Chrome and Firefox.

Now you are ready to run Selenium script. Type in the above python script (google search)
in a text editor such as NotePad and save as “google_search.py”. Run the command below
in a command window.

> py google_search.py

You will see Firefox browser starting up and performing a Google search.

1.3 Cross browser testing


The biggest advantage of Selenium over other web test frameworks, in my opinion, is
that it supports all major web browsers: Firefox, Chrome and Internet Explorer/Edge. The
browser market nowadays is more diversified (based on the StatsCounter³, the usage share
in December 2017 for Chrome, IE/Edge and Firefox are 64.7%, 12.2% and 11.9% respectively).
It is logical that all external facing web sites require serious cross-browser testing. Selenium
is a natural choice for this purpose, as it far exceeds other commercial tools and free test
frameworks..

Chrome

To run Selenium tests in Google Chrome, besides the Chrome browser itself, ChromeDriver
needs to be installed.
Installing ChromeDriver is easy: go to ChromeDriver site⁴.
³http://en.wikipedia.org/wiki/Usage_share_of_web_browsers
⁴https://sites.google.com/a/chromium.org/chromedriver/downloads
Introduction 6

Download the one for your target platform, unzip it and put chromedriver executable in
your PATH. To verify the installation, open a command window (terminal for Unix/Mac),
execute command chromedriver, You shall see:
Starting ChromeDriver 80.0.3987.16 (....) on port 9515
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent
access by malicious code.

The test script below opens a site in a new Chrome browser window and closes it one second
later.
from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get("http://testwisely.com/demo")
time.sleep(1) # wait 1 second
driver.quit()

For readers who can’t wait to see the test running, below is the command you need to use to
execute a test, which you can download from the book’s site (Python and selenium library
need to be installed first. See instructions towards the end of this chapter).
> python ch01_open_chrome.py

Firefox
Selenium tests requires Gecko Driver⁵ to drive Firefox. The test script below will open a web
site in a new Firefox window.
⁵https://github.com/mozilla/geckodriver/releases/
Introduction 7

from selenium import webdriver


driver = webdriver.Firefox()
driver.get("http://testwisely.com/demo")

Internet Explorer

Selenium requires IEDriverServer to drive IE browser. Its installation process is very similar
to ChromeDriver. IEDriverServer is available at https://www.selenium.dev/downloads⁶.
Choose the right one based on your windows version (32 or 64 bit).

When a tests starts to execute in IE, before navigating the target test site, you will see this
first:

Depending on the version of IE, configurations may be required. Please see IE and IEDri-
verServer Runtime Configuration⁷ for details.

from selenium import webdriver


driver = webdriver.Ie()
driver.get("http://testwisely.com/demo")

Edge

Edge is Microsoft’s new and default web browser on Windows 10. To drive Edge with
WebDriver, you need download Microsoft WebDriver⁸. After installation, you will find the
executable (MicrosoftWebDriver.exe) under Program Files folder, add it to your PATH.
However, I couldn’t get it working after installing a new version of Microsoft WebDriver.
One workaround is to specify the driver path in test scripts specifically:

⁶https://www.selenium.dev/downloads
⁷https://code.google.com/p/selenium/wiki/InternetExplorerDriver#Required_Configuration
⁸https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
Introduction 8

from selenium import webdriver


import time
import os

# copy MicrosoftWebDriver.exe to the test script directory


dir = os.path.dirname(__file__)
edge_path = dir + "\MicrosoftWebDriver.exe"
driver = webdriver.Edge(edge_path)
driver.get("http://testwisely.com/demo")

1.4 unittest - Python Unit Testing Framework


The above scripts drive browsers, strictly speaking, they are not tests. To make the effective
use of Selenium scripts for testing, we need to put them in a test syntax framework that
defines test structures and provides assertions (performing checks in test scripts). In this
book, I use unittest, also known as “PyUnit”, the unit testing framework for Python. Here is
an example.

import unittest
from selenium import webdriver

class FooBarTestCase(unittest.TestCase):

@classmethod
def setUpClass(cls):
cls.driver = webdriver.Chrome()

@classmethod
def tearDownClass(cls):
cls.driver.quit()

def setUp(self):
self.driver.get("http://travel.agileway.net")

def tearDown(self):
self.driver.find_element_by_link_text("Sign off").click()

def test_first_case(self):
self.assertEqual("Agile Travel", self.driver.title)
self.driver.find_element_by_name("username").send_keys("agileway")
# ...
Introduction 9

def test_second_case(self):
self.driver.find_element_by_id("register_link").click()
# ...
self.assertIn("Register", self.driver.find_element_by_tag_name("body").text)

The keywords class, setUpClass, setUp and def test_xxx define the structure of a test
script file.

• class FooBarTestCase(unittest.TestCase):
Test suite name for grouping related test cases.
• setUpClass() and tearDownClass().
Optional test statements run before and after all test cases, typically starting a new
browser window in setupClass and close it in tearDownClass.
• setUp() and tearDown().
Optional test statements run before and after each test case.
• def test_xxx(self):
Individual test cases.
• Assertions
assertEqual() and assertIn are PyUnit’s two assertion methods which are used to
perform checks. More assert methods⁹

You will find more about unittest from its home page¹⁰. However, I honestly don’t think it
is necessary. The parts used for test scripts are not much and quite intuitive. After studying
and trying out some examples, you will be quite comfortable with it.

1.5 Run recipe scripts


Test scripts for all recipes can be downloaded from the book site. They are all in ready-to-run
state. I include the target web pages/sites as well as Selenium test scripts. There are two kinds
of target web pages: local HTML files and web pages on a live site. Running tests written for
a live site requires Internet connection.
⁹https://docs.python.org/3/library/unittest.html#assert-methods
¹⁰https://docs.python.org/3/library/unittest.html
Introduction 10

Run tests in PyCharm IDE

The most convenient way to run one test case or a test suite is to do it in an IDE, such as
PyCharm.

When you have a large number of test cases, then the most effective way to run
all tests is done by a Continuous Integration process.

Find the test case

You can locate the recipe either by following the chapter or searching by name. There are
over 150 test cases in the recipes test project. Here is the quickest way to find the one you
want in PyCharm.
Select menu ‘Navigation’ → ‘Go to Symbol …’.

A pop up window lists all test cases in the project for your selection. The finding starts as
soon as you type.

Run individual test case

Move mouse to a line within a test case (starting def test_xxx)(self):). Right click and
select “Run ‘Unittest test_xxx’” to run this case.
Introduction 11

The below is a screenshot of execution panel when one test case failed,

Run all test cases in a test script file

You can also run all test cases in a test script file by right clicking the file name in the project
pane and select “Run ‘Unittests in test_file.py’”.
Introduction 12

The below is a screenshot of the execution panel when all test cases in a test script file passed,

Run tests from command line


One advantage of open-source test frameworks, such as Selenium, is FREEDOM. You can
edit the test scripts in any text editors and run them from a command line.
To run test cases in a test script file (named google_test.py), enter command
Exploring the Variety of Random
Documents with Different Content
At first when he lighted the lamp he turned the wick up far too
high, and there was so much smoke and so big a flame that he
could not possibly put the chimney in place. He turned it out slowly
and was more successful in his second attempt, although even then
he did not find the glass chimney at all easy to adjust. Proudly the
“Light of Home” sailed round the inverted soap-dish and the
smoking lamp. Still Daddy caught ’eaps an’ ’eaps of fish. But, alas! a
storm arose, and the poor “Light of Home” listed in a truly terrifying
manner.
The storm gave rise to a new idea. Daddy was no longer aboard
the lugger. It was Granfäather Tregennis instead. Daddy was just a
little new boy lying in a big fourposter bed. But there must be a light
in Granny’s window to help Granfäather to sail safely home.
Tommy was in luck. As a rule there was no candle in Mammy’s
bedroom, only the paraffin lamp. To-day there stood on the chest of
drawers the ladies’ china candlestick, fitted with a quite new candle.
Tommy pulled up a chair to the foot of the bed, lighted the candle
and put the candlestick on the chair. Then he tilted it a little so that
the light might shine through the rails at the foot of the bed, for the
foot of the bed was the window of Granny’s room.
While these preparations were afoot the “Light of Home” had
been lying neglected in the trough of a wave. Now she again began
to sail over the furrowed bed clothes. But the storm was telling on
her. Slowly but surely her outer coat was melting away, leaving
sticky brown streaks on Tommy’s fingers and on the snowy
whiteness of the clean bed-quilt.
“You hobjeck you! you article you! I’ll tell your fäather the
minute he comes in.”
The “Light of Home” slipped through Tommy’s fingers. The
Eddystone lurched over, fell from its soap-dish rock and was
engulfed in the quilty billows below. Mrs. Tregennis rushed from the
position she had taken up in the doorway, seized the lamp and
extinguished the flame.
Tommy’s eyes dilated with fear. “Now I shall get it somethin’
awful!” he thought, and shrank against the erstwhile raging sea.
For once words failed Mrs. Tregennis. She looked at the big bed,
whose counterpane was brown with chocolate streaks and black with
paraffin smuts. She looked at her son, sticky, smutty and subdued.
On the new white collar of the sailor blouse were the chocolate
imprints of his restless fingers. Down the right leg of the new long
trousers were splashes of grease. The room was thick with the
smoke from the lamp and the smell was vile.
It was not often that Tommy was really whipped, and when
Mammy opened the top long drawer of the chest of drawers with a
sharp little jerk the tears welled up slowly in his big blue eyes. When
she took from the drawer the supple cane that was so seldom used,
and advanced towards him with grim determination, he broke into
piteous sobs.
A quarter of an hour later a tearful Tommy sat limply on a chair
in the kitchen; he wore his old blue trousers and his old red jersey
top. Sunday though it was Mammy stood at the table and with
brown paper and a hot iron removed the splashes of grease from
the right leg of the new sailor suit. The dandy-go-risset suit of the
early morning!
A painful silence lasted for several moments, then:
“Do ee love I any more, Mammy?”
Mrs. Tregennis rested the hot iron on the stand and looked
fixedly at Tommy. “How can I love ee, Tommy Tregennis, when
you’m such a naughty boy.”
“No,” Tommy’s voice broke. “I don’t s’pose ee do love I any
more; but”—and now the voice was very pleading—“I do love ee
brave an’ much, Mammy, quite so much as that,” and the two
restless hands, from which all chocolate stains had been removed,
were held more than half a yard apart.
Mrs. Tregennis showed no signs of relenting but gave all her
attention to moving the iron lightly up and down over the stiff,
brown paper.
The kitchen door opened and Miss Margaret walked in. In
amazement she paused; first, because Tommy was in his very
everyday clothes; secondly, because Mrs. Tregennis was ironing on
Sunday afternoon. The ladies had been sitting down by the sea,
surrounded by Easter calm, and were ignorant of the grim tragedy
enacted in the Tregennis household.
Miss Margaret was horrified when she was put in possession of
the facts. “Oh, Tommy!” her voice was very expressive and her face
was very sad. “How more than dreadful it would have been if you’d
been all burned up to nothing. Burned right up to nothing at all, only
the soles of your new brown boots left lying upon the bedroom
floor.”
Tommy shuddered and looked down at his feet.
“What would your Daddy and Mammy have done then?” Miss
Margaret continued. “They’d have been left all alone just with the
soles of your boots.”
This amused Tommy. He laughed.
Already the tragedy was being relegated to the background of
his mind. He slipped off the chair, and, advancing to Mammy who
was folding up the trousers, offered her the piece of pink ribbon that
had harnessed the chocolate donkey to the chocolate cart.
“For keeps!” he explained.
The fact that Mammy accepted the gift was a sign that the feud
was ended.
Along the kitchen floor, over the linoleum, was a strip of old
carpet, put there partly to take the tread and partly to give a little
extra comfort and keep the feet warm at meal-times. In jumping
across the floor Tommy pushed this out of place.
“Mind my best Brussels!” warned Mammy, playfully, and Tommy
felt that he was indeed forgiven.
His joy thereupon became so exuberant that the strip of carpet
was kicked entirely out of place.
Then Mrs. Tregennis became firm again. “Put that carpet
straight to wanst,” she ordered, and reluctantly Tommy obeyed at
one end of the strip.
“Now here,” said Mammy, pointing to the disarranged part at
her feet.
“That be your end,” demurred Tommy, but the stern looks of
both Mammy and Miss Margaret compelled him to adjust that end
also.
Miss Margaret knew instinctively that in putting it to rights
Tommy meant to flick up the whole strip and so plunge headlong
into disgrace once more. With diplomacy and tact, therefore, and
apparently unintentionally, she stood right on the middle of the strip
and began to talk to Mrs. Tregennis.
Before Miss Margaret left the kitchen Tregennis came in from
the front. Once more the story of Tommy’s mishap was repeated.
Tregennis turned to Miss Margaret. “I shall have to take ’e in
hand myself, Miss,” he said slowly, “if so be as he isn’t a better boy.”
Miss Margaret left the kitchen and, smiling, told the Brown Lady
of the awesome threat. Tregennis was a loving and entirely lovable
man, but much too gentle, too simple and too kindly to cope with
Tommy’s boisterous daring.
Downstairs in the kitchen gloom had again descended. Tommy
stuck his hands in his pockets and looked up into his mother’s face.
“Tell-tit,” he said, “oh, tell-tit,” and with the full vigour of his sturdy
legs he kicked the carpet strip awry.
CHAPTER XIV

I T was more than a week since Tommy’s Ladies had come to


Draeth. Easter was over, and until Whitsuntide no more steamer-
loads of Plymouth trippers would visit the little town. On landing the
steamer passengers invariably followed the same plan. Presumably
during the short voyage they had had enough of the sea, for on
leaving the boat they at once trailed up the main street of Draeth,
either in scattering groups or in twos. The groups included children:
little girls with tightly curled hair and little boys in velvet suits.
Sometimes the twos held each other’s hands, spoke little and looked
down at the ground as they walked; sometimes they were parted by
the whole width of the roadway, each seemingly indifferent to the
presence of the other.
The groups looked in at the shop-windows until they were
hungry; then, carrying bulging paper-bags, they retraced their steps
and, sitting in sheltered corners among the rocks, looking out
beyond the island to the open sea, they ate stolidly until the bags
were empty. Later the tide came up and restored the beach to order,
carrying out, even beyond the breakwater of the island, all the litter
of paper bags, banana skins, orange peel, glass and tin—all
mercifully washed outwards to the horizon until they became
waterlogged and sank to the ocean floor.
On Easter Monday the ladies walked to a distant and secluded
part of the coast and were happy all the morning in avoiding the
rush of holiday-makers. From afar they watched the approach of the
thronged steamers, and speculated idly as to the probable number
of boatloads that would land. Because it was good for the watermen
they were glad that the steamers came.
As they were leaving the house after dinner, a weary lady had
approached them. Behind her stood another woman, equally weary,
and a pale-faced, meek-eyed man. “Excuse me,” the first weary lady
had said, addressing Miss Dorothea, “but will you be so very kind as
to tell me where we can find the stocks?” she spoke with nervous
eagerness. “You see, we are only here for the day.”
Miss Dorothea had directed her to the stocks just around the
corner, and had followed the Blue Lady down the alley. But she was
not to escape so easily. “Excuse me once more,” said the weary
stranger, somewhat out of breath with running after her, “but is
there anything else to be seen in Draeth; you see, we are only here
for the day.”
On the following Monday, as they were walking up from the
sands at dinner time, they were laughing over the Easter
reminiscences, and comparing the beauty and stillness around them
with the bustle and throng of the week before. Then they began to
speak of Mrs. Radford. They found it very difficult to avoid her,
although they had not responded to her early advances. Whenever
they left the house they were conscious that her eyes followed them
until they were out of sight; she stood, barely concealed by the
curtains of the window, to mark their return.
The Blue Lady was growing impatient; the unceasing spying
annoyed her.
The Brown Lady saw not only the humour, but also the pathos,
of Mrs. Radford’s actions. “But think, Margaret,” she said; “it isn’t
real ill-nature that makes her so. It’s just a sort of jealousy; we have
so much, and she has so little.”
“I don’t agree with you. She has a husband and a child, and
money enough to enable her to live without effort.”
“Yes, she has all that, but she lacks absolutely the joy of living.
You yourself possess this in so high a degree that you scarcely allow
for its absence in others.”
“Ah, well,” sighed the Blue Lady, “I really will try to be more
tolerant, but the woman irritates me beyond endurance.”
She ran upstairs to the sitting-room:
“Oh the wild joys of living,” she quoted, “the leaping from rock
to——”
Her good resolutions were forgotten, for there, curled up on the
sofa, sat Annabel. She was not an attractive child in appearance: she
was too tall for her age, and, in spite of the fact that she was five
years old, she spoke in a babyish manner which sounded unnatural
and was, indeed, the result of affectation.
She was the first to speak. “Miss Magalet, ’tan I have dinner wiv
’oo?”
“No, Annabel, you most certainly can not. Why don’t you speak
plainly—Tommy does. And you must never again come up here when
we are not in.”
“You have much nicer dinners than us,” continued the child; “me
never has g’evy and meat, only beans and fings.”
“Poor mite!” said the Brown Lady below her breath.
Annabel had wriggled off the sofa and was pointing to a gay
chocolate box on the mahogany wash-stand that served as a
sideboard. “’S dem for Tommy?” she asked.
The Blue Lady lost patience. “They were for Tommy,” she said,
quite sharply; “but I don’t think they’re very good; they don’t seem
quite fresh, so you can have them if you like.”
The child, completely satisfied, went downstairs to show her
mother the gift.
“It’s no good,” said the Blue Lady, ashamed of her unkindness to
a little child. “She’s exactly like her mother and I cannot like her.”
For dinner the ladies had ordered ox-tail soup, lamb and green
peas, gooseberry tart and cream. So much Mrs. Radford learned
when she peeped in at the kitchen door as Mrs. Tregennis was
dishing up the second course.
“What very extravagant dinners they order.”
Mrs. Tregennis took no notice of the remark, but, stooping,
closed the oven door, and, digging a fork into the joint, lifted it from
the tin to the hot dish waiting on the fender. At that moment the
upstairs bell rang. Mrs. Tregennis answered it and returned with the
plates and the soup-tureen.
Mrs. Radford raised the lid of the tureen. “What delicious soup!”
she remarked, “and what a lot they have left. They would never miss
it, Mrs. Tregennis, if you would let me have some.”
There was no reply.
“Won’t you give me just a little—just enough for Annabel?”
Then Mrs. Tregennis spoke. “I shouldn’t think of doing such a
thing!” she answered, indignantly. “Why, I wouldn’t take not even so
much as a crumb of theirs, not even for my own Tommy, no, not if
’twas ever so!”
Even then Mrs. Radford was not ashamed. “A few green peas
——” she began again.
“Not one green pea, ma’am,” replied Mrs. Tregennis, firmly, “and
you’ll excuse me for sayin’ it, ma’am, but I really cannot understand
as how you can ask for any such thing; so there’s where ’tis to.”
Mrs. Radford flushed hotly. “Well! you’ll see,” she said
vindictively, “they’re living at too grand a rate, they are. Their money
won’t last out, it won’t. You can’t say that you were not warned.”
Passing into her own room Mrs. Radford slammed the door,
while Mrs. Tregennis carried the lamb, green peas and baked
potatoes upstairs to the spendthrift ladies.
CHAPTER XV

F OR more than three weeks it had been very fine on land, but at
sea it was rough and stormy, and the water was churned up and
thick. For boulter-fishing in the spring the sea must be clear.
Because of the bad weather-conditions there was much poverty in
Draeth. Between the end of September and the third week in April
some of the fishermen had earned barely three pounds. Since
Christmas the boats had not once been able to put out to sea. This
meant that all through Lent, when the fish fetches record prices,
there had not been a single catch.
The poverty of the fisher-folk pressed heavily on the
tradespeople too. When children were almost starving they could not
refuse to supply the homes with food. Certainly they entered in their
credit ledgers the amounts that were due to them from this family or
that, but they well knew that in many cases the reckoning was so
great that it would take more than a lifetime to pay it off.
As it so often happens at times like these the most deserving
found the least relief. The Prynnes, the Tregennises, the Williamses,
the Darks and others shunned debt as they would have shunned the
plague. Rather than ask for food to be supplied to them on credit
they would starve. Day by day the hoard saved up against a rainy
day grew less; for you may be prepared to meet a rainy day, but
when the rainy day lengthens into a rainy month then you feel the
pinch. For many families in Draeth this was the time of fear. The
ever-present question was: How much longer was it possible to hold
out?
Then suddenly, when things were at their worst, the weather
changed. The wind slewed round to another quarter, the turbid
waters became clear, and the fisher-folk grew light-hearted, for at
last the boats would put out to sea.
It was on the Monday of the last week in April that the fleet
made preparations for sailing. Tregennis looked upon it as a lucky
omen that on that very morning he had caught a rat on the “Light of
Home.” For some days he had known the plaguey thing was there.
Down in the cuddy-hole he had found an old coat of his bitten
through in the sleeve. Some of the nets, too, had been gnawed in
places, and he had had to be busy mending tackle. It is a grave
matter when a rat boards a lugger, for there is no knowing how
many more may follow. The four men on the “Light of Home” had
laid trap after trap, temptingly baited, but without result.
Now this morning Tregennis had at last put an end to the
plaguey varmint. As this trouble was overcome it was taken by the
men as a sign that further good luck loomed ahead.
Miss Margaret went into the kitchen before breakfast and found
Mrs. Tregennis packing the basket of food for Tregennis to take to
sea.
“It do look a lot, don’t it, Miss? There isn’t much room on the
boat, so you has to get it packed up tight as can be. They did
oughter be back on Wednesday morning, but I puts in for a bit
longer than that in case.”
“If you find your store of food running short, Tregennis,” advised
Miss Margaret, “remember that you ought to chew a great number
of times, forty-five chews to each bit of food I think it is, and then
the supplies will last all the longer.”
“My dear life, Miss; ’e do just bolt his food.”
“Can’t seem to taste it, somehow, if I do keep it in my mouth,”
Tregennis explained.
“He do eat his food too fast, Miss; I never knoo anyone eat so
fast as ’e; I be always a-tellin’ ’e.”
“Well, he must practise this morning. Are you going to give him
ham for breakfast, Mrs. Tregennis?”
“’Am?—no, miss—I’ll ’am ’en. He haven’t been to sea and
caught no fish. If he don’t work neither shall he eat. That’s in the
Bible, isn’t it, Miss?”
“Something like it,” agreed Miss Margaret.
“Yes, ’tis there, for sure. If a man will not work neither shall he
eat. It don’t say nothin’ about a woman in like case.”
“Oh, well,” interrupted Tregennis, smiling good-humouredly.
“Will not work; but I will work when there’s work to be done—the
pity is so often we can’t.”
“You’re both evading this question of chewing,” Miss Margaret
complained. “It’s all the fashion now to chew. They say that if you
follow this plan you only need half the usual amount of food. You
see it all nourishes you then; otherwise half is wasted.”
“Sakes! Tom, you remember that!” admonished Mrs. Tregennis.
“’An you too, Tommy, my man. Come here an’ listen to your Mammy.
If there’s goin’ to be any savin’ in it every bite as you puts into your
mouth you chews on forty-five times—— If so be as you can count
so far,” she added, as an afterthought.
“One—two—three—four—five—six—seven,” began Tommy, in a
dreary, sing-song voice, with incatchings of the breath.
“That’ll do,” interposed Miss Margaret, hastily. “I am quite sure,
Tommy Tregennis, that you can count up to forty-five very nicely
indeed,” and, laughing, she went upstairs.
After breakfast the ladies came down to see the boats leave the
harbour with the tide.
“’Taint no good, Miss, after all,” Mrs. Tregennis called out
gloomily as they passed the kitchen door.
“Oh, Mrs. Tregennis, why? I’m so sorry! Has the wind changed
again?”
“Oh, not the fishin’, Miss, but the chewin’,” she hastened to
explain. “Tom and Tommy was both tryin’ hard but by the time
they’d chewed less an’ twenty chews they didn’t ’ave nothin’ left.”
“We was just chewin’ on nothin’,” added Tregennis, who was
drying his face on the runnerin’ towel.
“T’ad all slippen down,” volunteered Tommy, looking up from
lacing his boots.
Miss Margaret looked at them sorrowfully. “There, you see,” she
declaimed, “it is just the universal finding. You will not allow
yourselves to be improved! You do not wish to be nourished! You will
not chew! Thus you waste half, nay, more than half, of the food you
eat.”
Then, relapsing into her normal manner, “Perhaps I’m not quite
justified in speaking,” she admitted, “for I know quite definitely I
couldn’t chew forty-five times myself, and I haven’t been as
enterprising as you, for I’ve never even tried.”
Tregennis picked up the basket of food that had led to the
discussion, and Tommy and the ladies accompanied him to the quay
where he boarded the “Light of Home.”
Sitting in the sunshine on the rocks, Tommy’s Ladies watched
the fishing boats tack across to Polderry then veer slowly round and
sail in a south-westerly direction. From Tregennis they knew that the
fleet was making for Mevagissey, where they would shoot their nets
and hope to get a good catch for baiting the boulters. In those
waters they thought that the smaller fish, pollock, pilchards (not fit,
at this time of the year, for food), herring and whiting would be
plentiful.
To those who do not know, boulter-fishing seems a fairly easy
occupation. The boats sail away with something trawling after them
on the floor of the sea, and the fish is caught!
Actually it is one of the hardest bits of work a man can do. If
the first shoot of the nets is successful the boulter is baited without
delay, and the luggers may sail away at once far beyond the
Eddystone to the fishing-grounds some fifty miles from Draeth.
Often, however, it happens that the nets are shot two, three, or even
four times before the men have fish enough to bait the hooks.
The boulter is made up of thick, weighted ropes. As each
boulter is fitted with two thousand hooks, and as these hooks are
fastened to it with cotton-line about eight or nine feet apart, it
follows that the whole boulter is from three to four miles long.
All the two thousand hooks pass four times through the hands
of the men on the lugger. First of all they must be baited, and after
this they must be shot. To the end of the boulter that is shot first
from the boat a cork buoy bearing a flag is fastened. This is called
the dan. At the middle of the boulter is a second dan. “This,” as
Tregennis had explained to the ladies, “do give a second chanst, for
when once ’tis gone overboard you can’t never even say it do belong
to ee. Anythin’ may ’appen to ’e, you can’t never tell.”
When the fish is caught on the two thousand deadly hooks
these pass for the third time through the fishermen’s hands, for now
they must be hauled. Lastly, when the lugger is back in the harbour,
they must all be cleared, not cleared of the catch only, but of all the
mutilated bits of bait. Then they are thoroughly cleaned, carefully
coiled round and put away in readiness for the next time the boats
are afloat.
Miss Margaret and Miss Dorothea were discussing the heaviness
of the work and the hard lot of the fisher-folk as they watched the
luggers sail away round the curve of the coast towards Mevagissey
and the bait.
As they spoke a cormorant dived in front of them beneath the
water.
“There!” said Miss Dorothea, indignantly. “Just as if it wasn’t
enough for these people to have steam-trawlers, and weather and
dog-fish in array against them! And now the cormorants are coming
in flocks and are eating up all the smaller fish along the coast. It’s an
arrant shame!”
It was just one o’clock. The last lugger had rounded the curve.
The ladies picked up their books and walked slowly home over the
polished rocks and along the firm wide stretch of sand that grew still
wider as the tide flowed slowly out.
CHAPTER XVI

T HE day after the fishing boats put out there was a sudden
change in the weather. Little white horses rode in the bay. On
land the wind blew in sharp, fitful gusts. The watermen said that
there must be a fall of snow inland.
Towards evening Mrs. Tregennis grew restless and uneasy. After
fastening up the house for the night she slipped back the bolt, and,
throwing on a shawl, went down to the front and looked out
anxiously over the angry sea.
When she carried in the breakfast the following morning there
were deep shadows under her tired eyes.
“You didn’t sleep properly last night, now, did you?” asked Miss
Dorothea; and Mrs. Tregennis admitted that she had been awake for
many hours.
“I didn’t only partly undress,” she explained. “I felt somehow so
restless and onsettled inside o’ me. But ’tis all right now, Miss,” and
Mrs. Tregennis smiled brightly, “for the boats they be sighted I do
hear tell, and they’ll be here about eleven o’clock.”
Soon after eleven one by one the boats sailed up the harbour.
Most of the fishing families of Draeth were represented on the quay,
for there was much anxiety to find out at once if the first catch since
Christmas had been good.
TOWARDS EVENING MRS. TREGENNIS GREW
RESTLESS AND UNEASY, AND WENT DOWN TO
THE FRONT AND LOOKED OUT ANXIOUSLY
OVER THE ANGRY SEA.

Mrs. Tregennis did not go down. She was too busy to leave
home, but she sang light-heartedly as she went about her work.
“Where’s my Daddy to?” asked Tommy, when he came home
from school.
“Not come home yet, ma handsome.”
“Boats is in,” objected Tommy.
“Yes, my man, but I s’pose your Daddy’s busy cleanin’ up. Run
an’ find ’en, ma lovely, an’ tell ’en to come in quick an’ have dinner
afore he goes to bed.”
Tommy ran off to the quay and walked alongside, trying to pick
out his Daddy’s boat.
“Hallo, Tommy,” said Uncle Sam, who was hauling up water in a
bucket over the side of the ‘Henrietta.’
“Hallo,” replied Tommy, “I be lookin’ for my Daddy; where be
the ‘Light of Home,’ Uncle Sam?”
“Dear life, I don’t know! Up there ’appen,” and Uncle Sam
jerked his thumb in the direction of the bridge.
Tommy sped on. There was Uncle Harry in his boat and Uncle
Jim in his. But no Daddy and no “Light of Home” could Tommy find.
“Uncle Jim, do tell I, where be the ‘Light of Home’?”
“Sure I don’t know, Thomas, my son. Can’t ee find she?”
Tommy shook his head.
“Try down below,” and Uncle Jim waved vaguely towards the
mouth of the harbour.
“Been there,” Tommy demurred, “an’ Uncle Sam ’e said come up
’ere, ’e did.”
Uncle Jim was removing old bait from the boulter; he stopped
and scratched his head.
Tommy’s eyes grew large and puzzled.
In a few minutes the word passed round that the “Light of
Home” was missing, and with her were Tom and Jack Tregennis,
James Prynne and Billy Dark.
Tommy walked into the kitchen with a white, strained face.
“Mammy,” he said, and again, “Mammy.” Then he swallowed hard. “I
can’t find my Daddy and the’ Light of Home’ bain’t in.”
Mrs. Tregennis was kneeling in front of the fire, making toast.
She rose and turned fiercely on her son. “I’ll about half kill ee,
Tommy Tregennis,” she said, “if you come here scarin’ with such
tales as they. I don’t want none of that sort of yarn here. I’ll knock
ee flying!”
For a moment they looked into each other’s eyes. Then Tommy
flung himself on the floor in a passion of weeping, while Mrs.
Tregennis stood staring in front of her, still holding the toasting-fork
in her hand.
Awkwardly, and as if ashamed, Uncle Sam edged into the
kitchen.
“Don’t ee take on now, Ellen,” he admonished. “’Twill sure to be
all right; it be just——”
“Of course ’twill be all right, an’ righter than right,” she
interrupted, angrily. “’Tis but that fulish child. Get up, Tommy, and
come an’ have your dinner, or you’m be late to school.”
Tommy still lay on the floor, his face buried in his arms.
“Get up, I tell ee, or I’ll shift ee, my son.”
Then, as there was still no movement: “If you don’t get up to
wanst, Tommy Tregennis, I’ll tell your fäather the minute——”
The familiar threat ended abruptly, and Mrs. Tregennis turned
away, put down the toasting-fork and filled the kettle at the sink.
All through that weary Wednesday Draeth waited for the “Light
of Home” and still she did not come. There was a heavy fall of snow
inland, the papers said, and the wind at sea grew more and more
boisterous. On Thursday morning there was snow in Draeth itself,
the roofs were white, and it settled on the fields above the cliffs.
Still there was no sign of the “Light of Home.” Glasses swept the
horizon in vain. No sail was in sight!
Dozens of people were on the front looking out seaward the
whole day long. Women wept and little children were terrified.
All this time Mrs. Tregennis never left the house, but went about
her work with tight, colourless lips, and with unseeing eyes. At
school Tommy sat still and frightened, but his Mammy said ’twas
better as he should go.
Mrs. Radford attempted tactless consolation, but Tommy’s
Ladies behaved as far as possible in a normal way. Outside they
shunned the shifting throng on the front, because they dreaded
hearing the muttered conjectures. So they sat some little distance
apart on the rocks, straining—like all the rest of Draeth—straining
out to sea.
“If I were the parson here,” said Miss Margaret, “I should open
the church and ask all those people on the front to come in. I’d just
have one strong, simple prayer and sing ‘For those in peril on the
sea.’ I shouldn’t say anything to them because I should only cry if I
did.” Miss Margaret groped for her handkerchief and wiped away the
tears that were trickling down her cheek.
In the whole wide world there seemed to be one thing only that
really mattered, and this was that the “Light of Home” should sail
over the horizon and ride with the tide up the harbour to Draeth.
The remaining hours of the Thursday dragged with incredible
slowness. It was a relief when night came and there could be no
more weary gazing seaward for a few hours at least.
When Mrs. Tregennis brought the tea in the morning there was
a new look in her eyes.
“Well?” asked the ladies, fearfully.
“They’ve sighted the boat,” she said. Then her unnatural
composure gave way; she leaned up against the wall and sobbed.
Miss Margaret jumped out of bed, rescued the tray and put her
arms around her.
“You darling,” she said. “You’ve been just so brave, it’s been
wonderful.” And she and the Brown Lady cried too, cried until they
laughed, then laughed until they cried again.
Crowds waited on the Frying Pan and on the quay to see the
“Light of Home” come in. Her bows were knocked out with the
lashing of the wind and the sea. But they had got the fish! The men
were heavy with sleep, stunned with exposure, shaking with cold.
But they had got the fish!
Bit by bit their story was told. When they had anchored on the
Tuesday afternoon they had, of course, thrown out the boulter with
the anchor. About nine o’clock that night when they wanted to sail
along a bit they found the boulter had parted from the anchor. There
was nothing for it but to make their way to the dan, cast anchor
there and wait patiently until daylight. By this time all the other
boats were sailing home. They secured the boulter all right, but they
didn’t seem to have much fish. So they thought to wait a time
longer, sailed farther southwards and anchored again.
Then the wind had come up somethin’ awful. As their lugger
was not built for a heavy open sea, they reckoned to make for
home. But they found that the strong spring tide had swept the
boulter round so that it was firmly caught as ever was on some rock
or somethin’ at the bottom o’ the sea. In workin’ another man’s gear
you’d rather risk your life than leave the boulter behind! So again
there was nothin’ for it but to wait; wait this time until the heavy tide
turned and swept their boulter back again from the obstruction on
which it had caught.
Hours they had had to wait for this, and even then they couldn’t
get off. Ill-luck seemed to dog them, for once more the boulter
parted; this time in the middle. How long they were ’eavin’ an’ pullin’
an’ gropin’ they couldn’t rightly say. For more than twenty-four hours
they had had neither food nor fire. But they had got the fish and the
owner of the boat had his boulter right enough, and that alone was
a matter of twenty poun’ an’ more.
The catch of the “Light of Home” made a record sale. There, on
the quay, the fish was all arranged in heaps—congers, ray, skate,
cod, ling, hake, even a few turbot and halibut lying royally alone.
“There was certainly ’eaps of fish,” the auctioneer remarked,
“and good fish at that.”
“’Uman creatures’ lives,” Jack Chorley was heard to quote.
The auctioneer frowned him down, blew his nose and started.
“Beautiful fish, gentlemen,” thus suavely he addressed the
buyers. “Now what offers, gentlemen, for the beautiful ’eaps of
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade

Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.

Let us accompany you on the journey of exploring knowledge and


personal growth!

ebookname.com

You might also like