0% found this document useful (0 votes)
301 views

Test-Driven Development with React and TypeScript: Building Maintainable React Applications 2nd Edition Juntao Qiu pdf download

The document promotes various ebooks and textbooks available for download at ebookmass.com, including 'Test-Driven Development with React and TypeScript' by Juntao Qiu. It provides links to additional recommended titles related to React, TypeScript, and test-driven development. The document also includes copyright information and details about the book's content and structure.

Uploaded by

calidosaura
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
301 views

Test-Driven Development with React and TypeScript: Building Maintainable React Applications 2nd Edition Juntao Qiu pdf download

The document promotes various ebooks and textbooks available for download at ebookmass.com, including 'Test-Driven Development with React and TypeScript' by Juntao Qiu. It provides links to additional recommended titles related to React, TypeScript, and test-driven development. The document also includes copyright information and details about the book's content and structure.

Uploaded by

calidosaura
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 77

Download the full version and explore a variety of ebooks

or textbooks at https://ebookmass.com

Test-Driven Development with React and TypeScript:


Building Maintainable React Applications 2nd
Edition Juntao Qiu

_____ Tap the link below to start your download _____

https://ebookmass.com/product/test-driven-development-with-
react-and-typescript-building-maintainable-react-
applications-2nd-edition-juntao-qiu/

Find ebooks or textbooks at ebookmass.com today!


Here are some recommended products for you. Click the link to
download, or explore more at ebookmass.com

React and React Native - Fifth Edition Mikhail Sakhniuk

https://ebookmass.com/product/react-and-react-native-fifth-edition-
mikhail-sakhniuk/

■■■■■■ ■■ TypeScript■React■Node.js■webpack ■ Docker Frank


Zammetti

https://ebookmass.com/product/%e7%8e%b0%e4%bb%a3%e5%85%a8%e6%a0%88%e5%
bc%80%e5%8f%91-%e4%bd%bf%e7%94%a8-
typescript%e3%80%81react%e3%80%81node-
js%e3%80%81webpack-%e5%92%8c-docker-frank-zammetti/

Master React in 5 Days: Become a React Expert in Under a


Week Eric Sarrion

https://ebookmass.com/product/master-react-in-5-days-become-a-react-
expert-in-under-a-week-eric-sarrion/

Master React in 5 Days: Become a React Expert in Under a


Week Eric Sarrion

https://ebookmass.com/product/master-react-in-5-days-become-a-react-
expert-in-under-a-week-eric-sarrion-2/
Test-Driven Development in Go Simion

https://ebookmass.com/product/test-driven-development-in-go-simion/

React Hooks in Action MEAP 03 John Larsen [Larsen

https://ebookmass.com/product/react-hooks-in-action-meap-03-john-
larsen-larsen/

Hands-on Test-Driven Development: Using Ruby, Ruby on


Rails, and RSpec 1st Edition Greg Donald

https://ebookmass.com/product/hands-on-test-driven-development-using-
ruby-ruby-on-rails-and-rspec-1st-edition-greg-donald/

Hands-on Test-Driven Development: Using Ruby, Ruby on


Rails, and RSpec 1 / converted Edition Greg Donald

https://ebookmass.com/product/hands-on-test-driven-development-using-
ruby-ruby-on-rails-and-rspec-1-converted-edition-greg-donald/

Database-Driven Web Development: Learn to Operate at a


Professional Level with PERL and MySQL 2nd Edition Thomas
Valentine
https://ebookmass.com/product/database-driven-web-development-learn-
to-operate-at-a-professional-level-with-perl-and-mysql-2nd-edition-
thomas-valentine/
Test-Driven
Development with
React and TypeScript
Building Maintainable React
Applications

Second Edition

Juntao Qiu
Test-Driven
Development with
React and TypeScript
Building Maintainable React
Applications
Second Edition

Juntao Qiu
Test-Driven Development with React and TypeScript: Building
Maintainable React Applications

Juntao Qiu
Wantirna, 3152, VIC, Australia

ISBN-13 (pbk): 978-1-4842-9647-9 ISBN-13 (electronic): 978-1-4842-9648-6


https://doi.org/10.1007/978-1-4842-9648-6

Copyright © 2023 by Juntao Qiu


This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or
part of the material is concerned, specifically the rights of translation, reprinting, reuse of
illustrations, recitation, broadcasting, reproduction on microfilms or in any other physical way,
and transmission or information storage and retrieval, electronic adaptation, computer software,
or by similar or dissimilar methodology now known or hereafter developed.
Trademarked names, logos, and images may appear in this book. Rather than use a trademark
symbol with every occurrence of a trademarked name, logo, or image we use the names, logos,
and images only in an editorial fashion and to the benefit of the trademark owner, with no
intention of infringement of the trademark.
The use in this publication of trade names, trademarks, service marks, and similar terms, even if
they are not identified as such, is not to be taken as an expression of opinion as to whether or not
they are subject to proprietary rights.
While the advice and information in this book are believed to be true and accurate at the date of
publication, neither the authors nor the editors nor the publisher can accept any legal
responsibility for any errors or omissions that may be made. The publisher makes no warranty,
express or implied, with respect to the material contained herein.
Managing Director, Apress Media LLC: Welmoed Spahr
Acquisitions Editor: Divya Modi
Development Editor: James Markham
Coordinating Editor: Divya Modi
Cover designed by eStudioCalamar
Cover image by Pixabay
Distributed to the book trade worldwide by Springer Science+Business Media New York, 1
New York Plaza, Suite 4600, New York, NY 10004-1562, USA. Phone 1-800-SPRINGER, fax (201)
348-4505, e-mail orders-ny@springer-sbm.com, or visit www.springeronline.com. Apress Media,
LLC is a California LLC and the sole member (owner) is Springer Science + Business Media
Finance Inc (SSBM Finance Inc). SSBM Finance Inc is a Delaware corporation.
For information on translations, please e-mail booktranslations@springernature.com; for
reprint, paperback, or audio rights, please e-mail bookpermissions@springernature.com.
Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook
versions and licenses are also available for most titles. For more information, reference our Print
and eBook Bulk Sales web page at http://www.apress.com/bulk-sales.
Any source code or other supplementary material referenced by the author in this book is
available to readers on GitHub (github.com/apress). For more detailed information, please visit
http://www.apress.com/source-code.
Paper in this product is recyclable
To Mansi and Luna.
Table of Contents
About the Author�������������������������������������������������������������������������������xiii
About the Technical Reviewers����������������������������������������������������������xv
Acknowledgments����������������������������������������������������������������������������xvii
Foreword 1����������������������������������������������������������������������������������������xix
Foreword 2����������������������������������������������������������������������������������������xxi
Introduction�������������������������������������������������������������������������������������xxiii

Chapter 1: A Brief History of Test-Driven Development������������������������1


What Is Test-Driven Development?�����������������������������������������������������������������������1
The Red-Green-Refactor Cycle������������������������������������������������������������������������2
A Closer Look at Red-Green-Refactor�������������������������������������������������������������4
Types of TDD����������������������������������������������������������������������������������������������������5
Prerequisites of TDD����������������������������������������������������������������������������������������8
Other Techniques That Can Help Implement TDD������������������������������������������������10
Tasking����������������������������������������������������������������������������������������������������������10
Summary������������������������������������������������������������������������������������������������������������12
Further Reading��������������������������������������������������������������������������������������������������12

Chapter 2: Get Started with Jest��������������������������������������������������������15


Set Up the Environment��������������������������������������������������������������������������������������15
Install and Configure Jest������������������������������������������������������������������������������16
Jest at First Glance���������������������������������������������������������������������������������������������18
Basic Concepts in Jest����������������������������������������������������������������������������������21

v
Table of Contents

Using Matchers in Jest���������������������������������������������������������������������������������������25


Basic Usages�������������������������������������������������������������������������������������������������25
Matchers for Array and Object�����������������������������������������������������������������������27
The Powerful Function expect�����������������������������������������������������������������������28
Build Your Matchers���������������������������������������������������������������������������������������31
Mocking and Stubbing����������������������������������������������������������������������������������������34
jest.fn for Spying�������������������������������������������������������������������������������������������35
Mock Implementation������������������������������������������������������������������������������������35
Stub a Remote Service Call���������������������������������������������������������������������������36
Summary������������������������������������������������������������������������������������������������������������37

Chapter 3: Refactoring Essentials: The Basics You Need to Know����39


The Ten Most Common Refactorings������������������������������������������������������������������39
Let’s Talk the Problem – Code Smells�����������������������������������������������������������������40
Long Files������������������������������������������������������������������������������������������������������40
Big Props List������������������������������������������������������������������������������������������������41
Mixing Computation with Views��������������������������������������������������������������������42
Overuse of Mocks������������������������������������������������������������������������������������������43
Not Following Established Principles������������������������������������������������������������44
The Problem – ROT13�����������������������������������������������������������������������������������������45
The Initial Implementation����������������������������������������������������������������������������������45
The Top Ten Refactorings������������������������������������������������������������������������������������47
Step 1: Slide Statements�������������������������������������������������������������������������������48
Step 2: Extract Constant��������������������������������������������������������������������������������49
Step 3: Extract Function��������������������������������������������������������������������������������50
Step 4: Rename Parameter����������������������������������������������������������������������������51
Step 5: Rename Variable�������������������������������������������������������������������������������52
Step 6: Extract Function��������������������������������������������������������������������������������53

vi
Table of Contents

Step 7: Replace if-else with ?������������������������������������������������������������������������55


Step 8: Extract Function��������������������������������������������������������������������������������56
Step 9: Extract Parameter������������������������������������������������������������������������������57
Step 10: Extract Constant������������������������������������������������������������������������������58
Step 11: Slide Statements�����������������������������������������������������������������������������59
Step 12: Move Fields�������������������������������������������������������������������������������������60
Step 13: Function to Arrow Function�������������������������������������������������������������61
Step 14: Simplify Logic����������������������������������������������������������������������������������62
Summary������������������������������������������������������������������������������������������������������������63

Chapter 4: Test-Driven Development Essentials���������������������������������65


Writing Tests�������������������������������������������������������������������������������������������������������65
Using Given-When-Then to Arrange a Test����������������������������������������������������66
Triangulation Method������������������������������������������������������������������������������������������69
Example: Function addition���������������������������������������������������������������������������69
How to Do Tasking with TDD�������������������������������������������������������������������������������72
An Expression Parser for Tracking Progress��������������������������������������������������73
Applying TDD Step by Step����������������������������������������������������������������������������75
Keep Refactoring – Extract Functions to Files�����������������������������������������������78
Summary������������������������������������������������������������������������������������������������������������80

Chapter 5: Project Setup���������������������������������������������������������������������81


Application Requirements�����������������������������������������������������������������������������������81
Feature 1 – Book List������������������������������������������������������������������������������������82
Feature 2 – Book Detail���������������������������������������������������������������������������������83
Feature 3 – Searching�����������������������������������������������������������������������������������83
Feature 4 – Book Reviews�����������������������������������������������������������������������������84

vii
Table of Contents

Create the Project�����������������������������������������������������������������������������������������������84


Using create-react-app���������������������������������������������������������������������������������84
Material UI Library�����������������������������������������������������������������������������������������88
Install Cypress�����������������������������������������������������������������������������������������������91
Commit Code to Version Control��������������������������������������������������������������������95
Summary������������������������������������������������������������������������������������������������������������96

Chapter 6: Implement the Book List���������������������������������������������������97


Acceptance Tests for Book List���������������������������������������������������������������������������97
A List (of Books)��������������������������������������������������������������������������������������������97
Verify Book Name������������������������������������������������������������������������������������������99
Refactoring – Extract Function��������������������������������������������������������������������100
Refactoring – Extract Component����������������������������������������������������������������103
Talk to the Backend Server�������������������������������������������������������������������������������105
Stub Server��������������������������������������������������������������������������������������������������106
Async Request in Application����������������������������������������������������������������������108
Setup and Teardown������������������������������������������������������������������������������������110
Adding a Loading Indicator�������������������������������������������������������������������������������114
Refactor First�����������������������������������������������������������������������������������������������114
Define a React Hook������������������������������������������������������������������������������������118
Unit Tests of the Bookish Application����������������������������������������������������������������120
Unit Test with the React Testing Library������������������������������������������������������120
Summary����������������������������������������������������������������������������������������������������������123

Chapter 7: Implementing the Book Detail View��������������������������������125


Acceptance Tests����������������������������������������������������������������������������������������������125
Link to Detail Page��������������������������������������������������������������������������������������126
Verify Book Title on Detail Page�������������������������������������������������������������������126
Frontend Routing�����������������������������������������������������������������������������������������127

viii
Table of Contents

Unit Tests����������������������������������������������������������������������������������������������������������132
Refactoring��������������������������������������������������������������������������������������������������133
Book Detail Page�����������������������������������������������������������������������������������������137
File Structure�����������������������������������������������������������������������������������������������139
Testing Data������������������������������������������������������������������������������������������������������141
User Interface Refinement��������������������������������������������������������������������������������143
Using Grid System���������������������������������������������������������������������������������������144
Handling Default Value��������������������������������������������������������������������������������������146
A Failing Test with undefined����������������������������������������������������������������������146
One Last Change?���������������������������������������������������������������������������������������������149
Summary����������������������������������������������������������������������������������������������������������150

Chapter 8: Searching by Keyword����������������������������������������������������153


Acceptance Test������������������������������������������������������������������������������������������������153
One Step Further�����������������������������������������������������������������������������������������158
What Have We Done?����������������������������������������������������������������������������������162
Moving Forward – The Test Code Is As Important���������������������������������������������163
Summary����������������������������������������������������������������������������������������������������������167

Chapter 9: Introduction to State Management���������������������������������169


State Management��������������������������������������������������������������������������������������������170
A Typical Scenario of Building UI�����������������������������������������������������������������170
Pub-Sub Pattern������������������������������������������������������������������������������������������171
A Brief of Redux�������������������������������������������������������������������������������������������172
Decoupling Data and View���������������������������������������������������������������������������174
The Formula: view = f(state)�����������������������������������������������������������������������176
Implementing State Management���������������������������������������������������������������������178
Environment Setup��������������������������������������������������������������������������������������178
Define a Slice����������������������������������������������������������������������������������������������179

ix
Table of Contents

Fetching Data from Remote�������������������������������������������������������������������������181


Define the Store�������������������������������������������������������������������������������������������183
Migrate the Application�������������������������������������������������������������������������������������185
Book List Container�������������������������������������������������������������������������������������186
Refine the SearchBox����������������������������������������������������������������������������������187
Test Individual Reducers�����������������������������������������������������������������������������������189
Book Details Slice���������������������������������������������������������������������������������������������190
Do You Need a State Management Library?������������������������������������������������������193
Summary����������������������������������������������������������������������������������������������������������194

Chapter 10: Book Reviews����������������������������������������������������������������197


Business Requirements������������������������������������������������������������������������������������198
Start with an Empty List������������������������������������������������������������������������������198
Rendering a Static List��������������������������������������������������������������������������������200
Use the Review Component in BookDetail��������������������������������������������������201
Fulfill a Book Review Form��������������������������������������������������������������������������203
End-to-End Test�������������������������������������������������������������������������������������������������205
Define a Review Slice����������������������������������������������������������������������������������207
Adjust the Stub Server for Book Reviews����������������������������������������������������209
Refactoring��������������������������������������������������������������������������������������������������214
Add More Fields������������������������������������������������������������������������������������������������216
Review Editing��������������������������������������������������������������������������������������������������220
Save a Review – Action and Reducer����������������������������������������������������������223
Integration All Together��������������������������������������������������������������������������������227
Summary����������������������������������������������������������������������������������������������������������230

x
Table of Contents

Chapter 11: Behavior-Driven Development���������������������������������������231


Play with Cucumber������������������������������������������������������������������������������������������232
Install and Config cucumber Plugin�������������������������������������������������������������233
Live Document with cucumber�������������������������������������������������������������������������235
File Structure�����������������������������������������������������������������������������������������������235
The First Feature Specification��������������������������������������������������������������������235
Define the Steps������������������������������������������������������������������������������������������236
Book List������������������������������������������������������������������������������������������������������238
Searching����������������������������������������������������������������������������������������������������240
Review Page������������������������������������������������������������������������������������������������242
Summary����������������������������������������������������������������������������������������������������������244

Appendix A: Background of Testing Strategies��������������������������������245

Appendix B: A Short Introduction to TypeScript�������������������������������251

Index�������������������������������������������������������������������������������������������������259

xi
About the Author
Juntao Qiu is an accomplished software
developer renowned for his expertise
in producing high-quality and easily
maintainable code. He is committed to
helping individuals improve their code-
writing abilities and generously shares his vast
knowledge and experience through multiple
platforms, including books such as this one
and Maintainable React (Leanpub, 2022).
In addition, Juntao hosts a YouTube channel (@icodeit.juntao) where
he provides valuable insights, tips, and best practices for writing clean
code and performing refactoring. Juntao’s goal is to empower developers,
enabling them to reach their full potential and have a positive impact on
the software development industry.

xiii
About the Technical Reviewers
Jeff Friesen is a freelance teacher and
software developer with an emphasis on
Java. In addition to authoring Java I/O, NIO
and NIO.2 (Apress) and Java Threads and
the Concurrency Utilities (Apress), Jeff has
written numerous articles on Java and other
technologies (such as Android) for JavaWorld
(JavaWorld.com) – now InfoWorld (www.
infoworld.com/category/java/), informIT
(InformIT.com), Java.net (no longer in existence), SitePoint (SitePoint.
com), and other websites. Jeff can be contacted via his email address:
jefff@xplornet.ca.

Alexander Nnakwue has a background


in mechanical engineering and is a senior
software engineer with over seven years of
experience in various industries including
payments, blockchain, and marketing
technology. He is a published author for
professional JavaScript, a technical writer, and
a reviewer. He currently works as a software
engineer at Konecranes with the digital
experience team, working on machine data
and industrial cranes.
In his spare time, he loves to listen to music and enjoys the game of
soccer. He resides in Helsinki, Finland, with his lovely wife and son Kaobi.

xv
Acknowledgments
I am profoundly grateful to my ThoughtWorks colleagues for their
enthusiastic engagement and invaluable contributions during the
development of this book. Our project discussions were a fountain of
insight, enriching the narrative with an array of diverse perspectives. A
special acknowledgment goes to Evan Bottcher for his meticulous review
and for providing an eloquent foreword for the book.
Before embarking on the second edition, I reached out to my
newsletter (https://juntao.substack.com/) subscribers with a survey,
seeking their expectations for the new iteration. The response was
overwhelming and deeply informative – my heartfelt thanks go out to
those dedicated readers who took the time to provide their input.
I must extend my profound appreciation to the editorial team for their
indispensable support throughout the second edition’s journey. Their
expert advice has proven invaluable in refining the text, and it’s their
tireless dedication that has brought this project to fruition.
Finally, upon first sharing my book’s vision with my colleagues
at ThoughtWorks, the outpouring of valuable feedback I received –
spanning from minor typographical corrections to substantial technical
suggestions – was truly overwhelming. In particular, on a cool morning
in May 2020, I was greeted with an uplifting email from Hannah Bourke,
who not only expressed her appreciation for the book but also offered
her editing assistance as a native English speaker and fellow developer.
Her subsequent pull requests offered not just high-quality language
corrections but also insightful technical review comments from a learner’s
perspective.

xvii
Acknowledgments

Furthermore, I am indebted to Martin Fowler, a distinguished


developer and writer, who surprised me with detailed and insightful
feedback on my initial draft. Although the content of the book has
significantly evolved since that draft, the essence of his invaluable
comments is still palpably present. Heeded his advice, I’ve trimmed
nearly a quarter of the content to enhance clarity and readability,
removed unrelated code snippets from examples, and provided more
context around the code. Above all, the lesson of simplicity that I learned
from Martin has been invaluable – emphasizing a thorough exploration
of one topic at a time, rather than superficially touching upon every
possible aspect.
In summary, the journey to this book’s completion has been enriched
by the collective wisdom and support of countless individuals. Their
feedback, suggestions, and encouragement have been nothing short of
invaluable, for which I am eternally grateful.

xviii
Foreword 1
Sometimes, I find it hard to believe that it’s been more than two decades
since Kent Beck published Extreme Programming Explained including
Test-Driven Development (TDD) as a core practice. In the years since then,
the use of automated testing has become quite commonplace, something
that almost all developers are familiar with – however, the “Red-Green-­
Refactor” cycle of TDD is often missing. The reality is that building
software test first is not easy or trivial in real-world software development
and requires deliberate practice and usually someone experienced to
learn from.
At ThoughtWorks, my role is Head of Engineering – responsible for the
quality of the software that our teams produce for and with our clients.
We set a high standard for the “internal” quality of the code we produce,
wanting it to be maintainable and extensible so that it can quickly be
changed with confidence. Test-Driven Development is a default practice
in ThoughtWorks – our experience shows that the practice leads to better
software design and good confidence from a comprehensive automated
test suite.
In my years at ThoughtWorks, I’ve seen the phenomenal rise in the
importance of JavaScript and browser applications. In 2010, we advised
that the industry should treat JavaScript as a first-class language (www.
thoughtworks.com/radar/languages-and-frameworks/javascript-­
as-­a-first-class-language) on the ThoughtWorks Technology Radar,
applying all of the same engineering rigor as other platforms. As one of
the authors of the Technology Radar, I’ve seen and helped document the
explosion of tooling and frameworks in JavaScript, many of which have
been related to the area of test automation.

xix
Foreword 1

Test-Driven Development with React and TypeScript is a practical and


hands-on guide to learn TDD with React, the most prevalent browser
application framework in use today. It guides the reader through the
fundamentals of TDD with React by implementing a series of requirements
in a nontrivial example application. The book is fast-paced, so if you’re
unfamiliar with React and its friends, you’ll need to pause along the way
and do some research as the example application grows in features and
dependencies. Along the way, Juntao points out some “smells” or signs that
the approach can be improved – for example, cluttered code organization
or hard-to-maintain test data.
Read this book if you would like to learn by example from someone
who is an expert in using TDD to grow browser applications.

Evan Bottcher
March 2021

xx
Foreword 2
Landing in the middle of a React project that had very low test coverage,
in a team that had aspirations to improve it, but without a clear strategy
of how to go about it, I struggled to find resources that stepped out how to
approach testing for a frontend project. I couldn’t find a clear explanation
of how to implement Test-Driven Development for a UI, let alone
specifically for React. This book couldn’t have come at a better time.
There are a plethora of different testing methodologies and libraries
available just for React. The ones you choose will depend on many
things. This book doesn’t prescribe a particular solution but establishes
the purpose of tests in driving out specifications and suggests an overall
approach, with practical guidance and examples. Juntao provides a
holistic explanation of the purpose and implementation of Test-Driven
Development for React, demonstrating the benefits of moving testing
earlier in the process, improving the robustness and design of our code.
Juntao’s years of experience, his eagerness and passion for learning
and sharing his knowledge in a didactic way, help to make this a relevant,
practical, and engaging guide to follow and have given me confidence in
my own testing strategies.

Hannah Bourke
March 2021

xxi
Introduction
This comprehensive book is your ultimate guide to mastering Test-Driven
Development (TDD) in the context of React and TypeScript. Whether you're
a seasoned developer seeking to refine your skills or a newcomer eager to
embrace industry-standard practices, this book caters to all levels of expertise.
Spanning a wide range of topics, each chapter in this book is
thoughtfully designed to provide you with a deep understanding of TDD
principles and their application in real-world scenarios. Let's take a
glimpse into the chapters and their role in your learning journey:

Chapters 1 to 4: Setting Up the Foundation

In these early chapters, we lay the groundwork for


your TDD journey. We provide a brief history of
Test-Driven Development, allowing you to grasp
the underlying concepts and motivations. You'll
then dive into getting started with Jest, Cypress, and
the React Testing Library, equipping you with the
necessary tools to write effective tests.

Chapters 5 to 10: Implementing the Features

These chapters form the heart of the book, as we guide


you through the step-by-step implementation of key
features in our Bookish application. From building
the book list and book detail view to incorporating
search functionality, state management, and even
enabling user reviews, you'll gain invaluable hands-on
experience in applying TDD principles to build robust
and reliable React applications.

xxiii
Introduction

Chapter 11: Describing Acceptance Tests

In this final chapter, we explore the concept of


acceptance testing and introduce you to Behavior-
Driven Development (BDD). You'll learn how to
write acceptance tests that ensure your application
meets the desired behavior and satisfies stakeholder
requirements.

By following along with each chapter, you'll not only acquire the
knowledge and skills to excel in TDD but also experience the benefits
firsthand. Faster feedback cycles, improved code quality, enhanced
collaboration, and the confidence to make changes and add new features
are just a few of the advantages you'll gain.
Are you ready to embark on a transformative journey toward
becoming a more confident, efficient, and skilled developer? Test-Driven
Development with React and TypeScript: Building Maintainable React
Applications is your comprehensive companion. Let the power of TDD
guide your development process, elevate your coding skills, and lay the
foundation for a successful career in software development. Get ready to
dive in and unlock the full potential of TDD in your React projects.

xxiv
CHAPTER 1

A Brief History
of Test-Driven
Development
My purpose in writing this chapter is not to copy and paste cliches from
blogs or to make it seem like I was part of the historic events (such as the
Agile Manifesto or Extreme Programming activities) that led to the creation
of Test-Driven Development as a methodology – believe me, I’m not that old.
However, I do believe that providing context around the topics we’ll be
discussing in this book can be helpful. In this chapter, we’ll explore the basic
workflow of TDD and the various practical approaches used by different
schools of thought. If you prefer to jump straight into the code, feel free to do
so by navigating to the next chapter and getting your hands dirty.

What Is Test-Driven Development?


TDD is a software development methodology in which tests are written to
drive the development of an application. It was developed/rediscovered by
Kent Beck in the late 1990s as part of Extreme Programming1 and was well
discussed in his famous book Test-Driven Development: By Example.

1
https://martinfowler.com/bliki/ExtremeProgramming.html
© Juntao Qiu 2023 1
J. Qiu, Test-Driven Development with React and TypeScript,
https://doi.org/10.1007/978-1-4842-9648-6_1
Chapter 1 A Brief History of Test-Driven Development

In his book, Kent Beck describes two essential rules:

• Write new code only if you first have a failing


automated test

• Eliminate duplication

which leads to the steps of Red-Green-Refactor, which we will discuss


soon. The ultimate goal for these two rules is to write (as Ron Jeffries
describes) clean code that works.

The Red-Green-Refactor Cycle


Red-Green-Refactor is the core cycle of Test-Driven Development (TDD)
methodology. The cycle involves the following steps:

1. Red: Write a failing test that describes the desired


behavior of a specific feature or functionality. The
test should not pass yet as the functionality has not
yet been implemented.

2. Green: Write the minimum amount of production


code necessary to make the failing test pass. The
focus should be solely on passing the test, without
worrying about code quality or design.

3. Refactor: Improve the design of the production code


without changing its behavior, ensuring that all tests
continue to pass. This step includes optimizing
the code, removing duplication, and enhancing its
overall quality.

The cycle repeats with each new feature or functionality, with the goal
of producing high-quality code that meets the specified requirements
and is maintainable over time. The Red-Green-Refactor cycle (Figure 1-1)
emphasizes writing automated tests before writing any production code,
ensuring that the code is continually tested and improved as it evolves.
2
Chapter 1 A Brief History of Test-Driven Development

Figure 1-1. Test-Driven Development

At first glance, the principles may seem straightforward to follow.


However, the challenge with many principles is that they may not work
effectively for beginners. The principles are generally high level and
challenging to implement, as they lack specificity and detailed guidance.
For example, just knowing the principles will not help you to answer
questions like

• How can I write my very first test?

• What does enough code actually mean?

• When and how should I refactor?

• What refactoring techniques do I need to begin with?

This book aims to address these questions and equip you with the
knowledge and skills necessary to apply these techniques with confidence
in your daily workflow. By the end of the book, you should be well
equipped to implement the discussed techniques effectively.

3
Chapter 1 A Brief History of Test-Driven Development

A Closer Look at Red-Green-Refactor


Examining the Red-Green-Refactor cycle more closely reveals something
intriguing. To successfully integrate this method into our daily workflow,
we must consider several additional elements.

Figure 1-2. Test-Driven Development. Source: Wikipedia (https://


en.wikipedia.org/wiki/Test-driven_development)

Traditionally, TDD contains two major parts: quick implementation


and then refactoring. In practice, the tests for quick implementation are
not limited to the unit tests. They can be the acceptance tests as well –
these are higher-level tests that focus more on business value and the
end-user journey, without worrying too much about the technical details.
Implementing the acceptance tests first could be an even better idea.
Starting with acceptance tests ensures that the right things are
prioritized, and it provides confidence to developers when they want
to clean up and refactor the code in the later stage. Acceptance tests
are intended to be written from the end user’s perspective; a passing

4
Chapter 1 A Brief History of Test-Driven Development

acceptance test ensures the code meets the business requirement.


Additionally, it protects the developer from wasting time on false
assumptions or invalid requirements.
When applying TDD, you need to keep in mind a simple principle
from Extreme Programming: YAGNI, or You Aren’t Gonna Need It. YAGNI
can be very useful for protecting developers from wasting their valuable
time. Developers are very good at making assumptions around potential
requirement changes, and based on those assumptions, they may come
up with some unnecessary abstractions or optimizations that can make
the code more generic or reusable. The problem is that those assumptions
rarely turn out to be true. YAGNI emphasizes that you should not do it until
you have to.
However, in the refactor phase, you can implement those abstractions
and optimizations. Since you already have test coverage, it’s much safer to
do the cleanup then. Small refactors such as Change Class Name, Extract
Method, or Extract Class to a higher level – anything that helps to make the
code more generic and SOLID2 are now safer and easier to undertake.

Types of TDD
Although TDD is a broad and diverse concept with many variations and
different schools, such as UTDD, BDD, ATDD, and others, it traditionally
implied Unit Test–Driven Development or UTDD. However, the TDD
discussed in this book is an extended version of the conventional concept,
known as Acceptance Test–Driven Development (ATDD), which places a
strong emphasis on writing acceptance tests from the business perspective
and using them to drive the development of production code.

2
SOLID is an acronym for a set of principles in object-oriented design that
promote maintainability, flexibility, and extensibility of software. Each letter
in SOLID represents a principle: Single Responsibility Principle (SRP), Open/
Closed Principle (OCP), Liskov Substitution Principle (LSP), Interface Segregation
Principle (ISP) and Dependency Inversion Principle (DIP).

5
Chapter 1 A Brief History of Test-Driven Development

Having various tests in different layers can ensure that we are always
on the right track and have the correct functionality.

Implementing Acceptance Test–Driven Development


To put it succinctly, ATDD defines the behavior of software from the end
user’s perspective by prioritizing the business value of the application
rather than implementation details. Rather than validating that functions
are called at specific times with correct parameters, ATDD ensures that
when a user places an order, they receive their delivery on time.
We can merge the ATDD and UTDD into one diagram, as shown in
Figure 1-3.

Figure 1-3. Acceptance Test–Driven Development

The diagram describes the following steps:


1. Write an acceptance test and see it fail.
2. Write a unit test and see it fail.
3. Write code to make the unit test pass.
4. Refactor the code.
5. Repeat steps 2–4, until acceptance test passes.
6
Chapter 1 A Brief History of Test-Driven Development

When you look at this process closely, you find that during the
development stage, the acceptance test could be failing for quite some
time. The feedback loop turns out to be very long, and there is a risk that
an always-failed test means no test (protection) at all.
Developers could be confused about whether there are defects in the
implementation or whether there is any implementation at all.
To resolve this problem, you have to write acceptance tests in relatively
small chunks, testing a tiny slice of the requirement at a time. Alternatively,
you could use the “fake it until you make it” approach, as we are going to
use across this book.
The steps almost remain the same; only an extra fake step is added:

1. Write a failed acceptance test.

2. Make it pass in the most straightforward way (a fake


implementation).

3. Refactor based on any code smells (like hard-coded


data, magic number, etc.).

4. Add another new test based on a new requirement


(if we need a new acceptance test, go back to step 1;
otherwise, the process is just like traditional TDD).
Note that in the second step, you can use hard coding or a snippet of
static HTML to make the test pass. At first glance, that may look redundant,
but you will see the power of fake in the next few chapters.
The benefit of this variation is that when a developer is refactoring,
there is always a passing acceptance test protecting you from breaking
existing business logic. The drawback of this approach is that when a
developer doesn’t have enough experience, it can be difficult for them to
come up with clean code designs – they could keep the fake in some way
(e.g., a magic number, lack of abstractions, etc.).

7
Chapter 1 A Brief History of Test-Driven Development

Behavior-Driven Development
Another important variation of TDD is BDD, or Behavior-Driven
Development. Behavior-Driven Development is an agile practice that
encourages collaboration among different roles, developers, quality engineers,
business analysts, or even other interested parties in a software project.
Although BDD is to some extent a general idea about how software
development should be managed by both business interests and technical
insight, the practice of BDD involves some specialized tools. For example,
a Domain-Specific Language (DSL) is used to write tests in natural
language that can be easily understood by nontechnical people and can be
interpreted by code and executed behind the scenes.
The following code snippet of a BDD test case shows how a
requirement can be described:

Given there are `10` books in the library


When a user visits the homepage
Then they would see `10` books on the page
And each book would contain at least `name`, `author`, `price`
and `rating`

We’ll discuss this in detail in Chapter 10.

Prerequisites of TDD
To be candid, TDD can be a challenging methodology to apply. Several
prerequisites must be met before implementing it effectively. A crucial
prerequisite for TDD is a developer’s ability to detect code smells and
refactor them toward better design. Suppose, for example, you encounter
smelly code, such as a lack of abstractions or magic numbers, and are
unsure how to improve it. In that case, TDD alone may not be sufficient.
While the TDD workflow must be followed, there is a risk of creating
unmaintainable tests in addition to producing low-quality code.

8
Chapter 1 A Brief History of Test-Driven Development

Be Aware of Code Smell and Refactoring


In his book Refactoring: Improving the Design of Existing Code, Martin
Fowler listed 68 refactorings. I would recommend this book as almost
a mandatory prerequisite for anyone who values clean code and high-­
quality code. But don’t worry too much, some of the refactorings he
mentioned you may have already used in your daily work.
As mentioned earlier, a typical TDD workflow has three steps:

• A test case description requirement (specification)

• Some code to make the test pass

• Refactor the implementation and tests

It is a common misconception that test code is secondary or does


not hold the same level of importance as production code. However, I
would contend that test code is equally as crucial as production code.
Maintainable tests are crucial to people who have to make changes later on
or add new ones. Every time you refactor, make sure the changes made in
the production code are reflected in the test code.

Test First or Test Last


The hardest part of applying TDD in your daily workflow is that you have
to write tests before you start writing any production code. For most
developers, that’s not just different and counterintuitive but also breaks
their own way of working significantly.
Nevertheless, the key to applying TDD is that you should build the fast
feedback mechanism first. Once you have it, it doesn’t matter much if you
write the test first or last. By fast feedback, I mean that a method or an if-­
else branch can be tested in a very lightweight and effortless manner. If you
add tests after all the functionality has been completed, you are not doing
TDD by any means. Because you are missing the essential fast feedback
loop – seen as the most important thing in development – you may also be
missing the benefits promised by TDD.
9
Chapter 1 A Brief History of Test-Driven Development

By implementing a fast feedback loop, TDD ensures you are always


on the right track – safely. It also gives you sufficient confidence to do the
further code cleanup. And proper code cleanup can lead to a better code
design. Of course, the cleanup does not come automatically, it requires
extra time and effort. However, TDD is a great mechanism to protect you
from breaking the application when you are making changes.

Other Techniques That Can Help Implement TDD


For the beginner, it can be challenging when applying TDD as it sometimes
feels counterintuitive to test first. In practice, there are common reasons
for resistance to TDD:

• For simple tasks, they don’t need TDD.

• For complicated tasks, setting up the TDD mechanism


itself can be too difficult.

There are a lot of tutorials and articles out there to describe techniques
you should use to do TDD, and some may even involve describing how to
split tasks before implementing TDD. However, things discussed in those
tutorials are often oversimplified and can be hard to apply to a real-world
project directly.
For example, in a web application, both the interaction and a
considerable portion of business logic now exist in the frontend: the
UI. The traditional techniques of how to write a unit test to drive backend
logic are already outdated.

Tasking
Another critical skill required by TDD is splitting a large requirement into
smaller chunks through tasking. I would suggest every developer should
learn how to split requirements before they even start to write their first test.
We’ll discuss the tasking process in detail in the next chapter.

10
Chapter 1 A Brief History of Test-Driven Development

Maintaining a Simple Checklist


Usually, we can stop at the second round of splitting, since the Red-Green-­
Refactor is far too detailed in terms of tasking. And too granular tasks
means more management effort (tracking those tasks needs more energy).
To make the tasks visible, we can put it down on a post-it note and mark a
simple tick once it’s done (Figure 1-4).
By using this simple tool, you can then focus on what you’re going to
do and make the progress more accurate when you want to update it to
other team members (e.g., in the daily stand-up meeting). By saying a task
is 50% done, half of the items on the list are ticked off on the list you made
earlier.

Figure 1-4. Tasking with sticky notes

11
Chapter 1 A Brief History of Test-Driven Development

Summary
Refactoring depends on the sense and experience of identifying code
smells. Once you find a code smell, you can then apply the corresponding
refactoring technique. And then we may achieve maintainable, human-­
readable, extendable, and clean code along the way.
In the next chapter, we will introduce a concrete example to
demonstrate how to apply TDD step by step. Along with that example,
we will also cover the fundamental skills needed for implementing TDD,
including how to use the jest testing framework and how to do tasking with
real-world examples.

Further Reading
There is extensive debate around TDD – every now and then, you would
see people arguing about whether we need TDD or not or the right way
to implement TDD. I found the following articles are really helpful in
understanding some of those arguments:

• Uncle Bob has a great article3 discussing test first


or test last approaches. If you haven’t read it yet, I
highly recommend you do.

• The latest and most famous debate regarding TDD came


from David Heinemeier Hansson (DHH) (author of
Ruby on Rails), Kent Beck, and Martin Fowler; you can
find more here.4

3
https://blog.cleancoder.com/uncle-bob/2016/11/10/TDD-Doesnt-work.html
4
https://martinfowler.com/articles/is-tdd-dead/

12
Chapter 1 A Brief History of Test-Driven Development

Also, I highly recommend reading these books to build a solid


foundation for implementing TDD. Even if you decided not to utilize TDD,
these books are still highly recommended:

• Clean Code: A Handbook of Agile Software


Craftsmanship by Robert C. Martin5

• Refactoring: Improving the Design of Existing Code by


Martin Fowler6

5
www.goodreads.com/book/show/3735293-clean-code
6
https://martinfowler.com/books/refactoring.html

13
CHAPTER 2

Get Started with Jest


In this chapter, we’ll explore the key concepts and features of Jest,1 a
popular JavaScript testing framework. We’ll cover different types of
matchers, as well as the powerful and flexible expect and the useful mock
for unit testing. Moreover, we’ll learn how to organize our test suite in a
manner that’s easy to maintain, and we’ll explore best practices drawn
from real-world projects. By the end of the chapter, you’ll have a solid
understanding of Jest’s capabilities and how to use it effectively in your
own projects.
We will be using ES6 as the primary programming language throughout
this book.
To start off, we’ll walk you through setting up your environment
to write your first test. Throughout this book, we’ll be using ES6 as the
primary programming language.

Set Up the Environment


To follow along with the examples in this book, you’ll need to install node.
js, which we’ll be using as the primary platform. If you’re using a MacOS
with homebrew, you can install node by running the following command:

brew install node

1
https://jestjs.io/
© Juntao Qiu 2023 15
J. Qiu, Test-Driven Development with React and TypeScript,
https://doi.org/10.1007/978-1-4842-9648-6_2
Chapter 2 Get Started with Jest

If you’re running a different operating system or prefer another option,


you can download node from here.2
Once you have node installed locally, you can use npm (Node Package
Manager) to install node packages. npm is a binary program that comes
bundled with the node runtime.

Install and Configure Jest


Jest is a testing framework from Facebook that allows developers to write
reliable and fast-running tests in a more readable syntax. It can watch
changes in test/source files and rerun the necessary tests automatically.
This allows you to get quick feedback, and that is a crucial factor in
TDD. The speed of feedback can even determine whether TDD works
for you or not. Simply put, the faster tests can run, the more efficient
developers can be.
Let’s firstly create a folder for our experiment and initialize the folder
with a package.json to maintain all the following package installations:

mkdir jest-101
cd jest-101
npm init -y #init the current folder with default settings

When you install jest as a development dependency, it means that


jest is only needed during the development phase of your project and
is not required in the final production package. This helps to keep your
production package lean and focused on the essential components that
your users need.

npm install --save-dev jest

2
https://nodejs.org/en/download

16
Chapter 2 Get Started with Jest

After the installation, you can run jest --init to specify some default
settings, such as where jest should find the test files and the source code,
which environment (there are a lot) jest should run against (browser or
node for the backend), and so on. You have to answer some questions to
let jest understand your requirements; for now, let’s just accept all the
default settings by saying Yes for all the questions.
Note that if you have installed jest globally (with npm install jest -g),
you can use the following command to init the config directly:

jest --init

Otherwise, you will have to use the local installation by npx, which
looks for jest binary from node_modules/.bin/ and invokes it:

npx jest --init

For the sake of simplicity, we use node as a test environment, without


coverage report, and all other default settings like so:

npx jest --init

The following questions will help Jest to create a suitable configuration


for your project:

✔ Would you like to use Typescript for the configuration


file? ... no
✔ Choose the test environment that will be used for
testing › node
✔ Do you want Jest to add coverage reports? ... no
✔ Which provider should be used to instrument code for
coverage? › v8
✔ Automatically clear mock calls, instances, contexts and
results before every test? ... no
Configuration file created at /Users/juntao/icodeit/ideas/
jest-101/jest.config.js

17
Chapter 2 Get Started with Jest

To use TypeScript with jest-101, we need to first install and configure


babel. If you’re not familiar with babel, don’t worry – we’ll cover it in the
next chapter. In essence, babel is a tool that can translate TypeScript to
JavaScript that can be understood by the JavaScript runtime (Node).

npm install --save-dev babel-jest @babel/core @babel/preset-env

And then create a babel.config.js file in the root of our project (the
jest-101 folder), with the following content:

module.exports = {
  presets: [['@babel/preset-env', {targets: {node: 'current'}}]],
};

Now let’s enable TypeScript for our source code:

npm install --save-dev @babel/preset-typescript

And modify babel.config.js with the following content:

module.exports = {
  presets: [
    ['@babel/preset-env', {targets: {node: 'current'}}],
    '@babel/preset-typescript',
  ],
};

We’re all set now. It’s time to write our first Jest test.

Jest at First Glance


Cool, we’re ready to write some tests to verify that all parts can work
together now. Let’s create a folder named src and put two files in calc.
test.ts and calc.ts.

18
Chapter 2 Get Started with Jest

The file ends with "test.ts", that means it’s a pattern that jest will
recognize and treat them as tests, as defined in the jest.config.js we
generated previously:

  // The glob patterns Jest uses to detect test files


  // testMatch: [
  //   "**/__tests__/**/*.[jt]s?(x)",
  //   "**/?(*.)+(spec|test).[tj]s?(x)"
  // ],

Note the previous configuration is the default generated one, and


you can modify it to support other file name patterns. We’ll keep it as is
because ts is already included.
Let’s add some code to our calc.test.ts file:

import { add } from "./calc";

describe("calculator", function () {
  it("should be able to add two numbers", function () {
    expect(add(1, 2)).toEqual(3);
  });
});

In Jest, the describe function is used to group related tests together


and create a logical structure within your test suite. It provides a way to
organize and categorize tests based on a specific functionality, component,
or feature. And the it function, also known as a test case or a spec, is used
to define an individual test within your test suite. It represents a specific
scenario or behavior that you want to verify in your code.
The describe function takes two arguments: a description string and
a callback function. The description string is typically a brief explanation
of what the tests in that group are targeting. The callback function contains
the actual tests or nested describe blocks.

19
Chapter 2 Get Started with Jest

The it function takes two arguments: a description string and a


callback function. The description string describes what behavior or
outcome you are testing. The callback function contains the actual test
assertions or expectations.
In our example, the assertion expect(add(1, 2)).toEqual(3) checks
whether the result of calling the add function with arguments 1 and 2 is
equal to 3.
The function add is imported from another file and is implemented
like this:

function add(x: number, y: number) {


  return x + y;
}

export { add };

To run the test and check the result:

npm run test

And you would see something like this:

npm run test

> jest-101@1.0.0 test


> jest

PASS  src/calc.test.ts
  calculator
    ✓ add two numbers (1 ms)

Test Suites: 1 passed, 1 total


Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.259 s, estimated 1 s
Ran all test suites.

Fantastic, we now have our very first test up and running!


20
Chapter 2 Get Started with Jest

Basic Concepts in Jest


By utilizing the power of describe and it, you can structure your test suite,
enhance readability, and convey the intent of your tests more effectively.
These functions form the building blocks for creating comprehensive and
well-organized test suites in Jest. Let’s dive into the world of Jest testing
and harness the full potential of describe and it to ensure the quality and
reliability of your code.

Jest API: describe and it


For example, we can put all arithmetic into one group:

describe("calculator", () => {
  it("should perform addition", () => {});
  it("should perform subtraction", () => {});
  it("should perform multiplication", () => {});
  it("should perform division", () => {});
});

What’s more, we can nest describe functions like so:

describe("calculator", () => {
  describe("should perform addition", () => {
    it("adds two positive numbers", () => {});
    it("adds two negative numbers", () => {});
    it("adds one positive and one negative numbers", () => {});
  });
});

The fundamental idea is to group relevant tests together, so that the


test descriptions make sense for those who maintain them. It’s even more
helpful if you can describe the description (the first parameter for the
describe and it functions) using domain language within a business

21
Chapter 2 Get Started with Jest

context. This way, the test suite is easier to understand and more closely
aligned with the needs of the stakeholders who will ultimately benefit from
the software being tested.

Organize Your Tests Maintainer Friendly


For instance, when you are developing a hotel reservation application, the
tests read like this:

describe("Hotel Sunshine", () => {


  describe("Reservation", () => {
    it("should make a reservation when there are enough rooms
available", () => {});
    it("should warn the administrator when there are only 5
available rooms left", () => {});
  });

  describe("Checkout", () => {
    it("should check if any appliance is broken", () => {});
    it("should refund guest when checkout is earlier than
planned", () => {});
  });
});

You may occasionally find some duplicated code scattered in test


cases, for example, setting up a subject in each test is not uncommon:

describe("addition", () => {
  it("adds two positive numbers", () => {
    const options = {
      precision: 2,
    };

22
Chapter 2 Get Started with Jest

    const calc = new Calculator(options);


    const result = calc.add(1.333, 3.2);
    expect(result).toEqual(4.53);
  });

  it("adds two negative numbers", () => {


    const options = {
      precision: 2,
    };

    const calc = new Calculator(options);


    const result = calc.add(-1.333, -3.2);
    expect(result).toEqual(-4.53);
  });
});

Set Up and Tear Down


To reduce duplication, we can utilize the beforeEach function provided
by Jest to define reusable object instances. This function is automatically
invoked before Jest runs each test case. In our case, the calculator
instance can be used in all the test cases within the same describe block,
making it a convenient and efficient way to reduce repetition in our code:

describe("addition", () => {
  let calc = null;

  beforeEach(() => {
    const options = {
      precision: 2,
    };
    calc = new Calculator(options);
  });

23
Chapter 2 Get Started with Jest

  it("adds two positive numbers", () => {


    const result = calc.add(1.333, 3.2);
    expect(result).toEqual(4.53);
  });

  it("adds two negative numbers", () => {


    const result = calc.add(-1.333, -3.2);
    expect(result).toEqual(-4.53);
  });
});

You might be wondering if there is a corresponding function named


afterEach or if there is a way to handle cleanup tasks. The answer is yes!
Jest provides an afterEach function that can be used to perform any
necessary cleanup work after each test case has been run:

describe("database", () => {
  let db = null;

  beforeEach(() => {
    db.connect("localhost", "9999", "user", "pass");
  });

  afterEach(() => {
    db.disconnect();
  });
});

In this example, we are setting up a database connection before each


test case and closing it down afterward. In a real-world scenario, you might
also want to add a function to roll back any database changes or perform
other cleanup tasks in the afterEach step.

24
Chapter 2 Get Started with Jest

Furthermore, if you need something to be set up before all the test


cases start and then torn down after all of them are finished, you can use
the beforeAll and afterAll functions provided by Jest:

beforeAll(() => {
  db.connect("localhost", "9999", "user", "pass");
});

afterAll(() => {
  db.disconnect();
});

Using Matchers in Jest


Jest offers a variety of helper functions (matchers) that developers can use
for assertions when writing tests. These matchers allow you to test various
data types in different scenarios. We’ll start with some basic examples and
then move on to more advanced ones later on.

Basic Usages
Equality
toEqual and toBe may be the most common matchers you will find and use
in almost every test case. As the name implies, they are used to assert whether
values are equal to each other (the actual value and the expected value).
For example, it can be used for string, number, or composed objects:

it("basic usage", () => {


  expect(1 + 1).toEqual(2);
  expect("Juntao").toEqual("Juntao");
  expect({ name: "Juntao" }).toEqual({ name: "Juntao" });
});

25
Chapter 2 Get Started with Jest

and for toBe:

it("basic usage", () => {


  expect(1 + 1).toBe(2); // PASS
  expect("Juntao").toBe("Juntao"); // PASS
  expect({ name: "Juntao" }).toBe({ name: "Juntao" }); //FAIL
});

The last test will fail. For primitives like strings, numbers, and
booleans, you can use toBe to test the equality. While for Objects,
internally jest uses Object.is to check, which is strict and compares
objects by memory address. So if you want to make sure all the fields are
matching, use toEqual.

.not Method for Opposite Matching


Jest also provides .not that you can use to assert the opposite value:

it("basic usage", () => {


  expect(1 + 2).not.toEqual(2);
});

Sometimes, you might not want an exact match. Say you want a
string to be matching some particular pattern. Then you can use toMatch
instead:

it("match regular expression", () => {


  expect("juntao").toMatch(/\w+/);
});

In fact, you can write any valid regular expression:

it("match numbers", () => {


  expect("185-3345-3343").toMatch(/^\d{3}-\d{4}-\d{4}$/);
  expect("1853-3345-3343").not.toMatch(/^\d{3}-\d{4}-\d{4}$/);
});

26
Other documents randomly have
different content
The Project Gutenberg eBook of The Luckiest
Man in Denv
This ebook is for the use of anyone anywhere in the United States
and most other parts of the world at no cost and with almost no
restrictions whatsoever. You may copy it, give it away or re-use it
under the terms of the Project Gutenberg License included with this
ebook or online at www.gutenberg.org. If you are not located in the
United States, you will have to check the laws of the country where
you are located before using this eBook.

Title: The Luckiest Man in Denv

Author: C. M. Kornbluth

Illustrator: Ed Emshwiller

Release date: January 3, 2016 [eBook #50835]


Most recently updated: October 22, 2024

Language: English

Credits: Produced by Greg Weeks, Mary Meehan and the Online


Distributed Proofreading Team at http://www.pgdp.net

*** START OF THE PROJECT GUTENBERG EBOOK THE LUCKIEST


MAN IN DENV ***
The Luckiest Man in Denv

By SIMON EISNER

Illustrated by EMSH

[Transcriber's Note: This etext was produced from


Galaxy Science Fiction June 1952.
Extensive research did not uncover any evidence that
the U.S. copyright on this publication was renewed.]
To get the break of his life, all Reuben had to
do was turn the death trap into a jackpot!

May's man Reuben, of the eighty-third level, Atomist, knew there was
something wrong when the binoculars flashed and then went
opaque. Inwardly he cursed, hoping that he had not committed
himself to anything. Outwardly he was unperturbed. He handed the
binoculars back to Rudolph's man Almon, of the eighty-ninth level,
Maintainer, with a smile.
"They aren't very good," he said.
Almon put them to his own eyes, glanced over the parapet and swore
mildly. "Blacker than the heart of a crazy Angel, eh? Never mind;
here's another pair."
This pair was unremarkable. Through it, Reuben studied the
thousand setbacks and penthouses, of Denv that ranged themselves
below. He was too worried to enjoy his first sight of the vista from
the eighty-ninth level, but he let out a murmur of appreciation. Now
to get away from this suddenly sinister fellow and try to puzzle it out.
"Could we—?" he asked cryptically, with a little upward jerk of his
chin.
"It's better not to," Almon said hastily, taking the glasses from his
hands. "What if somebody with stars happened to see, you know?
How'd you like it if you saw some impudent fellow peering up at
you?"
"He wouldn't dare!" said Reuben, pretending to be stupid and
indignant, and joined a moment later in Almon's sympathetic
laughter.
"Never mind," said Almon. "We are young. Some day, who knows?
Perhaps we shall look from the ninety-fifth level, or the hundredth."
Though Reuben knew that the Maintainer was no friend of his, the
generous words sent blood hammering through his veins; ambition
for a moment.
He pulled a long face and told Almon: "Let us hope so. Thank you for
being my host. Now I must return to my quarters."
He left the windy parapet for the serene luxury of an eighty-ninth-
level corridor and descended slow moving stairs through gradually
less luxurious levels to his own Spartan floor. Selene was waiting,
smiling, as he stepped off the stairs.
She was decked out nicely—too nicely. She wore a steely hued
corselet and a touch of scent; her hair was dressed long. The
combination appealed to him, and instantly he was on his guard. Why
had she gone to the trouble of learning his tastes? What was she up
to? After all, she was Griffin's woman.
"Coming down?" she asked, awed. "Where have you been?"
"The eighty-ninth, as a guest of that fellow Almon. The vista is
immense."
"I've never been...." she murmured, and then said decisively: "You
belong up there. And higher. Griffin laughs at me, but he's a fool.
Last night in chamber we got to talking about you, I don't know how,
and he finally became quite angry and said he didn't want to hear
another word." She smiled wickedly. "I was revenged, though."
Blank-faced, he said: "You must be a good hand at revenge, Selene,
and at stirring up the need for it."
The slight hardening of her smile meant that he had scored and he
hurried by with a rather formal salutation.
Burn him for an Angelo, but she was easy enough to take! The
contrast of the metallic garment with her soft, white skin was
disturbing, and her long hair suggested things. It was hard to think of
her as scheming something or other; scheming Selene was displaced
in his mind by Selene in chamber.
But what was she up to? Had she perhaps heard that he was to be
elevated? Was Griffin going to be swooped on by the Maintainers?
Was he to kill off Griffin so she could leech onto some rising third
party? Was she perhaps merely giving her man a touch of the lash?
He wished gloomily that the binoculars-problem and the Selene-
problem had not come together. That trickster Almon had spoken of
youth as though it were something for congratulation; he hated being
young and stupid and unable to puzzle out the faulty binoculars and
the warmth of Griffin's woman.

The attack alarm roared through the Spartan corridor. He ducked


through the nearest door into a vacant bedroom and under the heavy
steel table. Somebody else floundered under the table a moment
later, and a third person tried to join them.
The firstcomer roared: "Get out and find your own shelter! I don't
propose to be crowded out by you or to crowd you out either and see
your ugly blood and brains if there's a hit. Go, now!"
"Forgive me, sir! At once, sir!" the latecomer wailed; and scrambled
away as the alarm continued to roar.
Reuben gasped at the "sirs" and looked at his neighbor. It was May!
Trapped, no doubt, on an inspection tour of the level.
"Sir," he said respectfully, "if you wish to be alone, I can find another
room."
"You may stay with me for company. Are you one of mine?" There
was power in the general's voice and on his craggy face.
"Yes, sir. May's man Reuben, of the eighty-third level, Atomist."
May surveyed him, and Reuben noted that there were pouches of
skin depending from cheekbones and the jaw line—dead-looking,
coarse-pored skin.
"You're a well-made boy, Reuben. Do you have women?"
"Yes, sir," said Reuben hastily. "One after another—I always have
women. I'm making up at this time to a charming thing called Selene.
Well-rounded, yet firm, soft but supple, with long red hair and long
white legs—"
"Spare me the details," muttered the general. "It takes all kinds. An
Atomist, you said. That has a future, to be sure. I myself was a
Controller long ago. The calling seems to have gone out of fashion—"
Abruptly the alarm stopped. The silence was hard to bear.
May swallowed and went on: "—for some reason or other. Why don't
youngsters elect for Controller any more? Why didn't you, for
instance?"
Reuben wished he could be saved by a direct hit. The binoculars,
Selene, the raid, and now he was supposed to make intelligent
conversation with a general.
"I really don't know, sir," he said miserably. "At the time there
seemed to be very little difference—Controller, Atomist, Missiler,
Maintainer. We have a saying, 'The buttons are different,' which
usually ends any conversation on the subject."
"Indeed?" asked May distractedly. His face was thinly filmed with
sweat. "Do you suppose Ellay intends to clobber us this time?" he
asked almost hoarsely. "It's been some weeks since they made a
maximum effort, hasn't it?"
"Four," said Reuben. "I remember because one of my best Servers
was killed by a falling corridor roof—the only fatality and it had to
happen to my team!"
He laughed nervously and realized that he was talking like a fool, but
May seemed not to notice.
Far below them, there was a series of screaming whistles as the
interceptors were loosed to begin their intricate, double basketwork
wall of defense in a towering cylinder about Denv.
"Go on, Reuben," said May. "That was most interesting." His eyes
were searching the underside of the steel table.
Reuben averted his own eyes from the frightened face, feeling some
awe drain out of him. Under a table with a general! It didn't seem so
strange now.
"Perhaps, sir, you can tell me what a puzzling thing, that happened
this afternoon, means. A fellow—Rudolph's man Almon, of the eighty-
ninth level—gave me a pair of binoculars that flashed in my eyes and
then went opaque. Has your wide experience—"
May laughed hoarsely and said in a shaky voice: "That old trick! He
was photographing your retinas for the blood-vessel pattern. One of
Rudolph's men, eh? I'm glad you spoke to me; I'm old enough to
spot a revival like that. Perhaps my good friend Rudolph plans—"
There was a thudding volley in the air and then a faint jar. One had
got through, exploding, from the feel of it, far down at the foot of
Denv.
The alarm roared again, in bursts that meant all clear; only one flight
of missiles and that disposed of.

The Atomist and the general climbed out from under the table; May's
secretary popped through the door. The general waved him out again
and leaned heavily on the table, his arms quivering. Reuben hastily
brought a chair.
"A glass of water," said May.
The Atomist brought it. He saw the general wash down what looked
like a triple dose of XXX—green capsules which it was better to leave
alone.
May said after a moment: "That's better. And don't look so shocked,
youngster; you don't know the strain we're under. It's only a
temporary measure which I shall discontinue as soon as things ease
up a bit. I was saying that perhaps my good friend Rudolph plans to
substitute one of his men for one of mine. Tell me, how long has this
fellow Almon been a friend of yours?"
"He struck up an acquaintance with me only last week. I should have
realized—"
"You certainly should have. One week. Time enough and more. By
now you've been photographed, your fingerprints taken, your voice
recorded and your gait studied without your knowledge. Only the
retinascope is difficult, but one must risk it for a real double. Have
you killed your man, Reuben?"
He nodded; It had been a silly brawl two years ago over precedence
at the refectory; he disliked being reminded of it.
"Good," said May grimly. "The way these things are done, your
double kills you in a secluded spot, disposes of your body and takes
over your role. We shall reverse it. You will kill the double and take
over his role."
The powerful, methodical voice ticked off possibilities and
contingencies, measures, and countermeasures. Reuben absorbed
them and felt his awe return. Perhaps May had not really been
frightened under the table; perhaps it had been he reading his own
terror in the general's face. May was actually talking to him of
backgrounds and policies. "Up from the eighty-third level!" he swore
to himself as the great names were uttered.
"My good friend Rudolph, of course, wants the five stars. You would
not know this, but the man who wears the stars is now eighty years
old and failing fast. I consider myself a likely candidate to replace
him. So, evidently, must Rudolph. No doubt he plans to have your
double perpetrate some horrible blunder on the eve of the election,
and the discredit would reflect on me. Now what you and I must do
—"
You and I—May's man Reuben and May—up from the eighty-third! Up
from the bare corridors and cheerless bedrooms to marble halls and
vaulted chambers! From the clatter of the crowded refectory to small
and glowing restaurants where you had your own table and servant
and where music came softly from the walls! Up from the scramble to
win this woman or that, by wit or charm or the poor bribes you could
afford, to the eminence from which you could calmly command your
pick of the beauty of Denv! From the moiling intrigue of tripping your
fellow Atomist and guarding against him tripping you to the heroic
thrust and parry of generals!
Up from the eighty-third!
Then May dismissed him with a speech whose implications were
deliriously exciting. "I need an able man and a young one, Reuben.
Perhaps I've waited too long looking for him. If you do well in this
touchy business, I'll consider you very seriously for an important task
I have in mind."

Late that night, Selene came to his bedroom.


"I know you don't like me," she said pettishly, "but Griffin's such a
fool and I wanted somebody to talk to. Do you mind? What was it
like up there today? Did you see carpets? I wish I had a carpet."
He tried to think about carpets and not the exciting contrast of
metallic cloth and flesh.
"I saw one through an open door," he remembered. "It looked odd,
but I suppose a person gets used to them. Perhaps I didn't see a
very good one. Aren't the good ones very thick?"
"Yes," she said. "Your feet sink into them. I wish I had a good carpet
and four chairs and a small table as high as my knees to put things
on and as many pillows as I wanted. Griffin's such a fool. Do you
think I'll ever get those things? I've never caught the eye of a
general. Am I pretty enough to get one, do you think?"
He said uneasily: "Of course you're a pretty thing, Selene. But carpets
and chairs and pillows—" It made him uncomfortable, like the
thought of peering up through binoculars from a parapet.
"I want them," she said unhappily. "I like you very much, but I want
so many things and soon I'll be too old even for the eighty-third level,
before I've been up higher, and I'll spend the rest of my life tending
babies or cooking in the creche or the refectory."
She stopped abruptly, pulled herself together and gave him a smile
that was somehow ghastly in the half-light.
"You bungler," he said, and she instantly looked at the door with the
smile frozen on her face. Reuben took a pistol from under his pillow
and demanded, "When do you expect him?"
"What do you mean?" she asked shrilly. "Who are you talking about?"
"My double. Don't be a fool, Selene. May and I—" he savored it
—"May and I know all about it. He warned me to beware of a
diversion by a woman while the double slipped in and killed me.
When do you expect him?"
"I really do like you," Selene sobbed. "But Almon promised to take
me up there and I knew when I was where they'd see me that I'd
meet somebody really important. I really do like you, but soon I'll be
too old—"
"Selene, listen to me. Listen to me! You'll get your chance. Nobody
but you and me will know that the substitution didn't succeed!"
"Then I'll be spying for you on Almon, won't I?" she asked in a
choked voice. "All I wanted was a few nice things before I got too
old. All right, I was supposed to be in your arms at 2350 hours."

It was 2349. Reuben sprang from bed and stood by the door, his
pistol silenced and ready. At 2350 a naked man slipped swiftly into
the room, heading for the bed as he raised a ten-centimeter
poignard. He stopped in dismay when he realized that the bed was
empty.
Reuben killed him with a bullet through the throat.

"But he doesn't look a bit like me," he said in bewilderment, closely


examining the face. "Just in a general way."
Selene said dully: "Almon told me people always say that when they
see their doubles. It's funny, isn't it? He looks just like you, really."
"How was my body to be disposed of?"
She produced a small flat box. "A shadow suit. You were to be left
here and somebody would come tomorrow."
"We won't disappoint him." Reuben pulled the web of the shadow
suit over his double and turned on the power. In the half-lit room, it
was a perfect disappearance; by daylight it would be less perfect.
"They'll ask why the body was shot instead of knifed. Tell them you
shot me with the gun from under the pillow. Just say I heard the
double come in and you were afraid there might have been a
struggle."
She listlessly asked: "How do you know I won't betray you?"
"You won't, Selene." His voice bit. "You're broken."
She nodded vaguely, started to say something and then went out
without saying it.
Reuben luxuriously stretched in his narrow bed. Later, his beds would
be wider and softer, he thought. He drifted into sleep on a half-
formed thought that some day he might vote with other generals on
the man to wear the five stars—or even wear them himself, Master of
Denv.
He slept healthily through the morning alarm and arrived late at his
regular twentieth-level station. He saw his superior, May's man Oscar
of the eighty-fifth level, Atomist, ostentatiously take his name. Let
him!
Oscar assembled his crew for a grim announcement: "We are going
to even the score, and perhaps a little better, with Ellay. At sunset
there will be three flights of missiles from Deck One."
There was a joyous murmur and Reuben trotted off on his task.
All forenoon he was occupied with drawing plutonium slugs from
hyper-suspicious storekeepers in the great rock-quarried vaults, and
seeing them through countless audits and assays all the way to
Weapons Assembly. Oscar supervised the scores there who
assembled the curved slugs and the explosive lenses into sixty-
kilogram warheads.
In mid-afternoon there was an incident. Reuben saw Oscar step aside
for a moment to speak to a Maintainer whose guard fell on one of the
Assembly Servers, and dragged him away as he pleaded innocence.
He had been detected in sabotage. When the warheads were in and
the Missilers seated, waiting at their boards, the two Atomists rode
up to the eighty-third's refectory.
The news of a near-maximum effort was in the air; it was electric.
Reuben heard on all sides in tones of self-congratulation: "We'll
clobber them tonight!"
"That Server you caught," he said to Oscar. "What was he up to?"
His commander stared. "Are you trying to learn my job? Don't try it, I
warn you. If my black marks against you aren't enough, I could
always arrange for some fissionable material in your custody to go
astray."
"No, no! I was just wondering why people do something like that."
Oscar sniffed doubtfully. "He's probably insane, like all the Angelos.
I've heard the climate does it to them. You're not a Maintainer or a
Controller. Why worry about it?"
"They'll brainburn him, I suppose?"
"I suppose. Listen!"

Deck One was firing. One, two, three, four, five, six. One, two, three,
four, five, six. One, two, three, four, five, six.
People turned to one another and shook hands, laughed and slapped
shoulders heartily. Eighteen missiles were racing through the
stratosphere, soon to tumble on Ellay. With any luck, one or two
would slip through the first wall of interceptors and blast close
enough to smash windows and topple walls in the crazy city by the
ocean. It would serve the lunatics right.
Five minutes later an exultant voice filled most of Denv.
"Recon missile report," it said. "Eighteen launched, eighteen perfect
trajectories. Fifteen shot down by Ellay first-line interceptors, three
shot down by Ellay second-line interceptors. Extensive blast damage
observed in Griffith Park area of Ellay!"
There were cheers.
And eight Full Maintainers marched into the refectory silently, and
marched out with Reuben.
He knew better than to struggle or ask futile questions. Any question
you asked of a Maintainer was futile. But he goggled when they
marched him onto an upward-bound stairway.
They rode past the eighty-ninth level and Reuben lost count, seeing
only the marvels of the upper reaches of Denv. He saw carpets that
ran the entire length of corridors, and intricate fountains, and mosaic
walls, stained-glass windows, more wonders than he could recognize,
things for which he had no name.
He was marched at last into a wood-paneled room with a great
polished desk and a map behind it. He saw May, and another man
who must have been a general—Rudolph?—but sitting at the desk
was a frail old man who wore a circlet of stars on each khaki
shoulder.
The old man said to Reuben: "You are an Ellay spy and saboteur."
Reuben looked at May. Did one speak directly to the man who wore
the stars, even in reply to such an accusation?
"Answer him, Reuben," May said kindly.
"I am May's man Reuben, of the eighty-third level, an Atomist," he
said.
"Explain," said the other general heavily, "if you can, why all eighteen
of the warheads you procured today failed to fire."
"But they did!" gasped Reuben. "The Recon missile report said there
was blast damage from the three that got through and it didn't say
anything about the others failing to fire."
The other general suddenly looked sick and May looked even kindlier.
The man who wore the stars turned inquiringly to the chief of the
Maintainers, who nodded and said: "That was the Recon missile
report, sir."
The general snapped: "What I said was that he would attempt to
sabotage the attack. Evidently he failed. I also said he is a faulty
double, somehow slipped with great ease into my good friend May's
organization. You will find that his left thumb print is a clumsy forgery
of the real Reuben's thumb print and that his hair has been artificially
darkened."
The old man nodded at the chief of the Maintainers, who said: "We
have his card, sir."
Reuben abruptly found himself being fingerprinted and deprived of
some hair.
"The f.p.s check, sir," one Maintainer said. "He's Reuben."
"Hair's natural, sir," said another.
The general began a rear-guard action: "My information about his
hair seems to have been inaccurate. But the fingerprint means only
that Ellay spies substituted his prints for Reuben's prints in the files
—"
"Enough, sir," said the old man with the stars. "Dismissed. All of you.
Rudolph, I am surprised. All of you, go."

Reuben found himself in a vast apartment with May, who was


bubbling and chuckling uncontrollably until he popped three of the
green capsules into his mouth hurriedly.
"This means the eclipse for years of my good friend Rudolph," he
crowed. "His game was to have your double sabotage the attack
warheads and so make it appear that my organization is rotten with
spies. The double must have been under post-hypnotic, primed to
admit everything. Rudolph was so sure of himself that he made his
accusations before the attack, the fool!"
He fumbled out the green capsules again.
"Sir," said Reuben, alarmed.
"Only temporary," May muttered, and swallowed a fourth. "But you're
right. You leave them alone. There are big things to be done in your
time, not in mine. I told you I needed a young man who could claw
his way to the top. Rudolph's a fool. He doesn't need the capsules
because he doesn't ask questions. Funny, I thought a coup like the
double affair would hit me hard, but I don't feel a thing. It's not like
the old days. I used to plan and plan, and when the trap went snap it
was better than this stuff. But now I don't feel a thing."
He leaned forward from his chair; the pupils of his eyes were black
bullets.
"Do you want to work?" he demanded. "Do you want your world
stood on its head and your brains to crack and do the only
worthwhile job there is to do? Answer me!"
"Sir, I am a loyal May's man. I want to obey your orders and use my
ability to the full."
"Good enough," said the general. "You've got brains, you've got push.
I'll do the spade work. I won't last long enough to push it through.
You'll have to follow. Ever been outside of Denv?"
Reuben stiffened.
"I'm not accusing you of being a spy. It's really all right to go outside
of Denv. I've been outside. There isn't much to see at first—a lot of
ground pocked and torn up by shorts and overs from Ellay and us.
Farther out, especially east, it's different. Grass, trees, flowers. Places
where you could grow food.
"When I went outside, it troubled me. It made me ask questions. I
wanted to know how we started. Yes—started. It wasn't always like
this. Somebody built Denv. Am I getting the idea across to you? It
wasn't always like this!
"Somebody set up the reactors to breed uranium and make
plutonium. Somebody tooled us up for the missiles. Somebody wired
the boards to control them. Somebody started the hydroponics tanks.
"I've dug through the archives. Maybe I found something. I saw
mountains of strength reports, ration reports, supply reports, and yet
I never got back to the beginning. I found a piece of paper and
maybe I understood it and maybe I didn't. It was about the water of
the Colorado River and who should get how much of it. How can you
divide water in a river? But it could have been the start of Denv, Ellay,
and the missile attacks."
The general shook his head, puzzled, and went on: "I don't see
clearly what's ahead. I want to make peace between Denv and Ellay,
but I don't know how to start or what it will be like. I think it must
mean not firing, not even making any more weapons. Maybe it
means that some of us, or a lot of us, will go out of Denv and live a
different kind of life. That's why I've clawed my way up. That's why I
need a young man who can claw with the best of them. Tell me what
you think."
"I think," said Reuben measuredly, "it's magnificent—the salvation of
Denv. I'll back you to my dying breath if you'll let me."
May smiled tiredly and leaned back in the chair as Reuben tip-toed
out.

What luck, Reuben thought—what unbelievable luck to be at a


fulcrum of history like this!
He searched the level for Rudolph's apartment and gained admission.
To the general, he said: "Sir, I have to report that your friend May is
insane. He has just been raving to me, advocating the destruction of
civilization as we know it, and urging me to follow in his footsteps. I
pretended to agree—since I can be of greater service to you if I'm in
May's confidence."
"So?" said Rudolph thoughtfully. "Tell me about the double. How did
that go wrong?"
"The bunglers were Selene and Almon. Selene because she alarmed
me instead of distracting me. Almon because he failed to recognize
her incompetence."
"They shall be brainburned. That leaves an eighty-ninth-level vacancy
in my organization, doesn't it?"
"You're very kind, sir, but I think I should remain a May's man—
outwardly. If I earn any rewards, I can wait for them. I presume that
May will be elected to wear the five stars. He won't live more than
two years after that, at the rate he is taking drugs."
"We can shorten it," grinned Rudolph. "I have pharmacists who can
see that his drugs are more than normal strength."
"That would be excellent, sir. When he is too enfeebled to discharge
his duties, there may be an attempt to rake up the affair of the
double to discredit you. I could then testify that I was your man all
along and that May coerced me."
They put their heads together, the two saviors of civilization as they
knew it, and conspired ingeniously long into the endless night.
*** END OF THE PROJECT GUTENBERG EBOOK THE LUCKIEST MAN
IN DENV ***

Updated editions will replace the previous one—the old editions will
be renamed.

Creating the works from print editions not protected by U.S.


copyright law means that no one owns a United States copyright in
these works, so the Foundation (and you!) can copy and distribute it
in the United States without permission and without paying
copyright royalties. Special rules, set forth in the General Terms of
Use part of this license, apply to copying and distributing Project
Gutenberg™ electronic works to protect the PROJECT GUTENBERG™
concept and trademark. Project Gutenberg is a registered trademark,
and may not be used if you charge for an eBook, except by following
the terms of the trademark license, including paying royalties for use
of the Project Gutenberg trademark. If you do not charge anything
for copies of this eBook, complying with the trademark license is
very easy. You may use this eBook for nearly any purpose such as
creation of derivative works, reports, performances and research.
Project Gutenberg eBooks may be modified and printed and given
away—you may do practically ANYTHING in the United States with
eBooks not protected by U.S. copyright law. Redistribution is subject
to the trademark license, especially commercial redistribution.

START: FULL LICENSE


THE FULL PROJECT GUTENBERG LICENSE
PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK

To protect the Project Gutenberg™ mission of promoting the free


distribution of electronic works, by using or distributing this work (or
any other work associated in any way with the phrase “Project
Gutenberg”), you agree to comply with all the terms of the Full
Project Gutenberg™ License available with this file or online at
www.gutenberg.org/license.

Section 1. General Terms of Use and


Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand, agree
to and accept all the terms of this license and intellectual property
(trademark/copyright) agreement. If you do not agree to abide by all
the terms of this agreement, you must cease using and return or
destroy all copies of Project Gutenberg™ electronic works in your
possession. If you paid a fee for obtaining a copy of or access to a
Project Gutenberg™ electronic work and you do not agree to be
bound by the terms of this agreement, you may obtain a refund
from the person or entity to whom you paid the fee as set forth in
paragraph 1.E.8.

1.B. “Project Gutenberg” is a registered trademark. It may only be


used on or associated in any way with an electronic work by people
who agree to be bound by the terms of this agreement. There are a
few things that you can do with most Project Gutenberg™ electronic
works even without complying with the full terms of this agreement.
See paragraph 1.C below. There are a lot of things you can do with
Project Gutenberg™ electronic works if you follow the terms of this
agreement and help preserve free future access to Project
Gutenberg™ electronic works. See paragraph 1.E below.
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.

More than just a book-buying platform, we strive to be a bridge


connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.

Join us on a journey of knowledge exploration, passion nurturing, and


personal growth every day!

ebookmasss.com

You might also like