Deprecated: Using ${var} in strings is deprecated, use {$var} instead in /usr/home/rpearse/public_html/wiki/includes/GlobalFunctions.php on line 2077
Deprecated: preg_match(): Passing null to parameter #2 ($subject) of type string is deprecated in /usr/home/rpearse/public_html/wiki/includes/libs/rdbms/lbfactory/LBFactory.php on line 697
Warning: session_name(): Session name cannot be changed after headers have already been sent in /usr/home/rpearse/public_html/wiki/includes/Setup.php on line 803
Deprecated: Return type of MediaWiki\Session\PHPSessionHandler::open($save_path, $session_name) should either be compatible with SessionHandlerInterface::open(string $path, string $name): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/PHPSessionHandler.php on line 180
Deprecated: Return type of MediaWiki\Session\PHPSessionHandler::close() should either be compatible with SessionHandlerInterface::close(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/PHPSessionHandler.php on line 195
Deprecated: Return type of MediaWiki\Session\PHPSessionHandler::read($id) should either be compatible with SessionHandlerInterface::read(string $id): string|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/PHPSessionHandler.php on line 209
Deprecated: Return type of MediaWiki\Session\PHPSessionHandler::write($id, $dataStr) should either be compatible with SessionHandlerInterface::write(string $id, string $data): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/PHPSessionHandler.php on line 237
Deprecated: Return type of MediaWiki\Session\PHPSessionHandler::destroy($id) should either be compatible with SessionHandlerInterface::destroy(string $id): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/PHPSessionHandler.php on line 343
Deprecated: Return type of MediaWiki\Session\PHPSessionHandler::gc($maxlifetime) should either be compatible with SessionHandlerInterface::gc(int $max_lifetime): int|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/PHPSessionHandler.php on line 364
Deprecated: MapCacheLRU implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in /usr/home/rpearse/public_html/wiki/includes/libs/MapCacheLRU.php on line 37
Deprecated: Return type of Wikimedia\Rdbms\IResultWrapper::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/libs/rdbms/database/resultwrapper/IResultWrapper.php on line 70
Deprecated: Return type of Wikimedia\Rdbms\IResultWrapper::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/libs/rdbms/database/resultwrapper/IResultWrapper.php on line 80
Deprecated: Return type of Wikimedia\Rdbms\IResultWrapper::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/libs/rdbms/database/resultwrapper/IResultWrapper.php on line 75
Deprecated: Return type of Wikimedia\Rdbms\ResultWrapper::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/libs/rdbms/database/resultwrapper/ResultWrapper.php on line 116
Deprecated: Return type of Wikimedia\Rdbms\ResultWrapper::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/libs/rdbms/database/resultwrapper/ResultWrapper.php on line 89
Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated in /usr/home/rpearse/public_html/wiki/includes/libs/rdbms/database/Database.php on line 618
Deprecated: Return type of MediaWiki\Session\Session::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 625
Deprecated: Return type of MediaWiki\Session\Session::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 631
Deprecated: Return type of MediaWiki\Session\Session::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 643
Deprecated: Return type of MediaWiki\Session\Session::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 637
Deprecated: Return type of MediaWiki\Session\Session::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 655
Deprecated: Return type of MediaWiki\Session\Session::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 649
Deprecated: Return type of MediaWiki\Session\Session::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 665
Deprecated: Return type of & MediaWiki\Session\Session::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 678
Deprecated: Return type of MediaWiki\Session\Session::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 688
Deprecated: Return type of MediaWiki\Session\Session::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /usr/home/rpearse/public_html/wiki/includes/session/Session.php on line 693
Deprecated: Optional parameter $style declared before required parameter $ts is implicitly treated as a required parameter in /usr/home/rpearse/public_html/wiki/vendor/wikimedia/timestamp/src/ConvertibleTimestamp.php on line 227
Deprecated: Creation of dynamic property ApiMain::$mCommit is deprecated in /usr/home/rpearse/public_html/wiki/includes/api/ApiMain.php on line 292
Warning: Cannot modify header information - headers already sent by (output started at /usr/home/rpearse/public_html/wiki/includes/GlobalFunctions.php:2077) in /usr/home/rpearse/public_html/wiki/includes/Feed.php on line 294
Warning: Cannot modify header information - headers already sent by (output started at /usr/home/rpearse/public_html/wiki/includes/GlobalFunctions.php:2077) in /usr/home/rpearse/public_html/wiki/includes/Feed.php on line 300
Warning: Cannot modify header information - headers already sent by (output started at /usr/home/rpearse/public_html/wiki/includes/GlobalFunctions.php:2077) in /usr/home/rpearse/public_html/wiki/includes/WebResponse.php on line 72
Warning: Cannot modify header information - headers already sent by (output started at /usr/home/rpearse/public_html/wiki/includes/GlobalFunctions.php:2077) in /usr/home/rpearse/public_html/wiki/includes/WebResponse.php on line 72
Warning: Cannot modify header information - headers already sent by (output started at /usr/home/rpearse/public_html/wiki/includes/GlobalFunctions.php:2077) in /usr/home/rpearse/public_html/wiki/includes/WebResponse.php on line 72 https://roger-pearse.com/wiki/api.php?action=feedcontributions&feedformat=atom&user=Roger+PearseEncyclopedia of Syriac Literature - User contributions [en]2025-04-03T10:00:24ZUser contributionsMediaWiki 1.33.0https://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/Attis_Sources&diff=3058User:Roger Pearse/Attis Sources2022-03-07T15:19:16Z<p>Roger Pearse: /* Literary Sources */</p>
<hr />
<div>These are the sources for our knowledge of Attis.<br />
<br />
=Literary Sources=<br />
<br />
==Herodotus, 5th century BC==<br />
<br />
In [http://www.sacred-texts.com/cla/hh/hh1030.htm Herodotus, book 1, 34-45], there is a rambling story about Atys, son of Croesus, accidentally killed by a spear while hunting. In his Cybele and Attis, M. J. Vermaseren considers whether this is part of the myth of Attis. [http://www.dur.ac.uk/Classics/histos/1998/lewis.html This link] asserts that it is.<br />
<br />
But on looking at the text, the account is very dissimilar from any other account. Does anything but the similarity of name tie the two together?<br />
<br />
==Catullus, 84 BC – ca. 54 BC==<br />
<br />
[http://www.vroma.org/~hwalker/VRomaCatullus/063.html Catullus, Poem 63]:<br />
<br />
<pre><br />
Borne in his swift bark over deep seas,<br />
Attis, when eagerly with speedy foot he reached the Phrygian woodland,<br />
and entered the goddess’ abodes, shadowy, forest-crowned;<br />
there, goaded by raging madness, bewildered in mind,<br />
he cast down from him with sharp flint-stone the burden of his member.<br />
So when she felt her limbs to have lost their manbood,<br />
still with fresh blood dabbling the face of the ground,<br />
swiftly with snowy bands she seized the light timbrel,<br />
your timbrel, Cybele, thy mysteries, Mother,<br />
and shaking with soft fingers the hollow oxhide<br />
thus began she to sing to her companions tremulously:<br />
“Come away, ye Gallae, go to the mountain forests of Cybele together,<br />
together go, wandering herd of the lady of Dindymus,<br />
who swiftly seeking alien homes as exiles,<br />
followed my rule as I led you in my train,<br />
endured the fast-flowing brine and the savage seas,<br />
and unmanned your bodies from utter abhorrence of love,<br />
cheer ye your Lady’s heart with swift wanderings.<br />
Let dull delay depart from your mind; go together, follow<br />
to the Phrygian house of Cybele, to the Phrygian forests of the goddess,<br />
where the noise of cymbals sounds, where timbrels re-echo,<br />
where the Phrygian flute-player blows a deep note on his curved reed,<br />
where the Maenads ivy-crowned toss their heads violently,<br />
where with shrill yells they shake the holy emblems,<br />
where that wandering company of the goddess is wont to rove,<br />
whither for us ’tis meet to hasten with rapid dances.”<br />
So soon as Attis, woman yet no true one, chanted thus to her companions,<br />
the revellers suddenly with quivering tongues yell aloud,<br />
the light timbrel rings again, clash again the hollow cymbals,<br />
swiftly to green Ida goes the rout with hurrying foot.<br />
Then too frenzied, panting, uncertain, wanders, gasping for breath,<br />
attended by the timbrel, Attis, through the dark forests their leader,<br />
as a heifer unbroken starting aside from the burden of the yoke.<br />
Fast follow the Gallae their swift-footed leader.<br />
So when they gained the house of Cybele, faint and weary,<br />
after much toil they take their rest without bread;<br />
heavy sleep covers their eyes with drooping weariness,<br />
the delirious madness of their mind departs in soft slumber.<br />
But when the sun with the flashing eyes of his golden face<br />
lightened the clear heaven, the firm lands, the wild sea,<br />
and chased away the shades of night with eager tramping steeds refreshed,<br />
then Sleep fled from wakened Attis and quickly was gone;<br />
him the goddess Pasithea received in her fluttering bosom.<br />
So after soft slumber, freed from violent madness,<br />
as soon as Attis himself in his heart reviewed his own deed,<br />
and saw with clear mind what lie had lost and where he was,<br />
with surging mind again he sped back to the waves.<br />
There, looking out upon the waste seas with streaming eyes,<br />
thus did she piteously address her country with tearful voice:<br />
” O my country that gavest me life! O my country that barest me!<br />
leaving whom, all wretch! as runaway servants leave their masters,<br />
I have borne my foot to the forests of Ida,<br />
to live among snows and frozen lairs of wild beasts,<br />
and visit in my frenzy all their lurking-dens,<br />
– where then or in what region do I think thy place to be, O my country?<br />
Mine eyeballs unbidden long to turn their gaze to thee<br />
while for a short space my mind is free from wild frenzy.<br />
I, shall I from my own home be borne far away into these forests?<br />
from my country, my possessions, my friends, my parents, shall I be?<br />
absent from the market, the wrestling-place, the racecourse, the playground?<br />
unhappy, all unhappy heart, again, again must thou complain.<br />
For what form of human figure is there which I had not?<br />
I, to be a woman–who was a stripling, I a youth, I a boy,<br />
I was the flower of the playground, I was once the glory of the palaestra:<br />
mine were the crowded doorways, mine the warm thresholds,<br />
mine the flowery garlands to deck my house<br />
when I was to leave my chamber at sunrise.<br />
I, shall I now be called–what? a handmaid of the gods, a ministress of Cybele?<br />
I a Maenad, I part of myself, a barren man shall I be?<br />
I, shall I dwell in icy snow-clad regions of verdant Ida,<br />
I pass my life under the high summits of Phrygia,<br />
with the hind that haunts the woodland, with the boar that ranges the forest?<br />
now, now I rue my deed, now, now I would it were undone.”<br />
From his rosy lips as these words issued forth,<br />
bringing a new message to both ears of the gods,<br />
then Cybele, loosening the fastened yoke from her lions,<br />
and goading that foe of the herd who drew on the left, thus speaks:<br />
“Come now,” she says, “come, go fiercely, let madness hunt him hence<br />
bid him hence by stroke of madness hie him to the forests again,<br />
him who would be too free, and run away from my sovereignty.<br />
Come, lash back with tail, endure thy own scourging,<br />
make all around resound with bellowing roar,<br />
shake fiercely on brawny neck thy ruddy mane.”<br />
Thus says wrathful Cybele, and with her hand unbinds the yoke.<br />
The monster stirs his courage and rouses him to fury of heart;<br />
he speeds away, he roars, with ranging foot he breaks the brushwood.<br />
But when he came to the watery stretches of the white-gleaming shore,<br />
and saw tender Attis by the smooth spaces of the sea,<br />
he rushes at him–madly flies Attis to the wild woodland.<br />
There always for all his lifetime was he a handmaid.<br />
Goddess, great goddess, Cybele, goddess, lady of Dindymus<br />
far from my house be all thy fury, O my queen<br />
others drive thou in frenzy, others drive thou to madness.<br />
</pre><br />
<br />
==Diodorus Siculus, 1st century BC==<br />
<br />
[http://penelope.uchicago.edu/Thayer/E/Roman/Texts/Diodorus_Siculus/3D*.html Diodorus Siculus, History, 3.58.4-59.1]:<br />
<br />
58. However, an account is handed down also that this goddess was born in Phrygia. For the natives of that country have the following myth: In ancient times Meïon became king of Phrygia and Lydia; and marrying Dindymê he begat an infant daughter, but being unwilling to rear her he exposed her on the mountain which was called Cybelus. There, in accordance with some divine providence, both the leopards and some of the other especially ferocious wild beasts offered their nipples to the child and so gave it nourishment, and some women who were tending the flocks in that place witnessed the happening, and being astonished at the strange event took up the babe and called her Cybelê after the name of the place. The child, as she grew up, excelled in both beauty and virtue and also came to be admired for her intelligence; for she was the first to devise the pipe of many reeds and to invent cymbals and kettledrums with which to accompany the games and the dance, and in addition she taught how to heal the sicknesses of both flocks and little children by means of rites of purification; in consequence, since the babes were saved from death by her spells and were generally taken up in her arms, her devotion to them and affection for them led all the people to speak of her as the “mother of the mountain.” The man who associated with her and loved her more than anyone else, they say, was Marsyas the physician, who was admired for his intelligence and chastity; and a proof of his intelligence they find in the fact that he imitated the sounds made by the pipe of many reeds and carried all its notes over into the flute, and as an indication of his chastity they cite his abstinence from sexual pleasures until the day of his death.<br />
<br />
Now Cybelê, the myth records, having arrived at full womanhood, came to love a certain native youth who was known as Attis, but at a later time received the appellation Papas; with him she consorted secretly and became with child, and at about the same time her parents recognized her as their child. Consequently she was brought up into the palace, and her father welcomed her at the outset under the impression the she was a virgin, but later, when he learned of her seduction, he put to death her nurses and Attis as well and cast their bodies forth to lie unburied; whereupon Cybelê, they say, because of her love for the youth and grief over the nurses, became frenzied and rushed out of the palace into the countryside. And crying aloud and beating upon a kettledrum she visited every country alone, with hair hanging free, and Marsyas, out of pity for her plight, voluntarily followed her and accompanied her in her wanderings because of the love which he had formerly borne her. … And Apollo, they say, laid away both the lyre and the pipes as a votive offering in the cave of Dionysus, and becoming enamoured of Cybelê joined in her wanderings as far as the land of the Hyperboreans.<br />
<br />
But, the myth goes on to say, a pestilence fell upon human beings throughout Phrygia and the land ceased to bear fruit, and when the unfortunate people inquired of the god how they might rid themselves of their ills he commanded them, it is said, to bury the body of Attis and to honour Cybelê as a goddess. Consequently the physicians, since the body had disappeared in the course of time, made an image of the youth, before which they sang dirges and by means of honours in keeping with his suffering propitiated the wrath of him who had been wronged; and these rites they continue to perform down to our own lifetime. As for Cybelê, in ancient times they erected altars and performed sacrifices to her yearly; and later they built for her a costly temple in Pisinus of Phrygia, and established honours and sacrifices of the greatest magnificence, Midas their king taking part in all these works out of his devotion to beauty; and beside the statue of the goddess they set up panthers and lions, since it was the common opinion that she had first been nursed by these animals.<br />
<br />
Such, then, are the myths which are told about Mother of the God both among the Phrygians and by the Atlantians who dwell on the coast of the ocean.<br />
<br />
==Ovid, 1st century AD==<br />
<br />
[http://www.tkline.freeserve.co.uk/OvidFastiBkFour.htm Ovid, Fasti, 4.221-224]:<br />
<br />
<pre><br />
… I said ‘Where did this urge to cut off<br />
Their members come from?’ As I ended, the Muse spoke:<br />
‘In the woods, a Phrygian boy, Attis, of handsome face,<br />
Won the tower-bearing goddess with his chaste passion.<br />
She desired him to serve her, and protect her temple,<br />
And said: “Wish, you might be a boy for ever.”<br />
He promised to be true, and said: “If I’m lying<br />
May the love I fail in be my last love.”<br />
He did fail, and in meeting the nymph Sagaritis,<br />
Abandoned what he was: the goddess, angered, avenged it.<br />
She destroyed the Naiad, by wounding a tree,<br />
Since the tree contained the Naiad’s fate.<br />
Attis was maddened, and thinking his chamber’s roof<br />
Was falling, fled for the summit of Mount Dindymus.<br />
Now he cried: “Remove the torches”, now he cried:<br />
“Take the whips away”: often swearing he saw the Furies.<br />
He tore at his body too with a sharp stone,<br />
And dragged his long hair in the filthy dust,<br />
Shouting: “I deserved this! I pay the due penalty<br />
In blood! Ah! Let the parts that harmed me, perish!<br />
Let them perish!” cutting away the burden of his groin,<br />
And suddenly bereft of every mark of manhood.<br />
His madness set a precedent, and his unmanly servants<br />
Toss their hair, and cut off their members as if worthless.’<br />
So the Aonian Muse, eloquently answering the question<br />
I’d asked her, regarding the causes of their madness.<br />
</pre><br />
<br />
[https://ovid.lib.virginia.edu/trans/Metamorph10.htm#484521419 Ovid, Metamorphoses (X.103-5)]:<br />
<br />
You came, also, ... the pliant palms, the winner’s prize; and you, the shaggy-topped pine tree, armed with needles, sacred to Cybele, mother of the gods, since Attis exchanged his human form for you, and hardened in your trunk.<br />
<br />
==Pausanias, 2nd century AD==<br />
<br />
[http://books.google.co.uk/books?dq=pausanias+description+of+greece&pg=PA191&id=p6oAAAAAYAAJ&ots=mmAB61GsT0 Pausanius, Guide to Greece, 7.17.5]:<br />
<br />
The Achaian city Dyme is distant about four hundred stadia from Larissus… Besides this the Dymaei have a temple of Minerva, and a statue of the goddess, which is very ancient. They have also another temple sacred to the mother Dindymene, and Attes. But who Attes is, I have not been able to discover, because it is. an arcane affair. Hermesianax, indeed, a writer of elegies, says, that he was the son of the Phrygian Calaus, and that he was produced by his mother incapable of begetting children. That when he arrived at manhood he migrated to Lydia, and established there the orgies of the Great Mother. And that he was so highly honoured by the goddess, that it excited the indignation of Jupiter, who sent a boar into the Lydian fields, by which other Lydians were destroyed, and Attes himself was slain. The Gauls who inhabit Pesinus, confirm by their conduct the truth of this relation, for they cannot bear to touch swine. However, they report things concerning Attes far different from the above.<br />
<br />
Jupiter, say they, while he was asleep emitted his seed on the earth; this in process of time produced a daemon with twofold private parts, viz. with the parts of man and woman united. The name of this daemon was Agdistis: and the gods, in consequence of being terrified at him, cut off his virile parts. From these parts an almond tree was produced, the fruit of which, when ripe, the daughter of the river Sangarius gathered and concealed in her bosom. The fruit, however, immediately vanished, and she became pregnant. As the result of her pregnancy, she was delivered of a boy, who being left in the woods was educated by a goat, and who, as he grew in years, possessed a beauty surpassing that of the human form, and through which Agdistis fell in love with him. But when he arrived at manhood, his friends sent him to Pesinus, in order that he might marry the daughter of the king. Here, as they were singing the nuptial song, Agdistis presented himself before them, and Attes becoming insane, cut off his private parts. The king’s daughter, too, that was given to Attes, cut off her privities. But Agdistis was grieved that Attes had acted in this manner, and obtained of Jupiter that no part of the body of Attes should either become putrid or waste away. And such are the particulars which are reported about Attes.<br />
<br />
==Lucian, 2nd century AD==<br />
<br />
[http://www.sacred-texts.com/cla/luc/tsg/tsg07.htm Lucian, ''De Dea Syria''. Chapters. 50-51]:<br />
<br />
50. On certain days a multitude flocks into the temple, and the Galli in great numbers, sacred as they are, perform the ceremonies of the men and gash their arms and turn their backs to be lashed. Many bystanders play on the pipes the while many beat drums; others sing divine and sacred songs. All this performance takes place outside the temple, and those engaged in the ceremony enter not into the temple.<br />
<br />
51. During these days they are made Galli. As the Galli sing and celebrate their orgies, frenzy falls on many of them and many who had come as mere spectators afterwards are found to have committed the great act. I will narrate what they do. Any young man who has resolved on this action, strips off his clothes, and with a loud shout bursts into the midst of the crowd, and picks up a sword from a number of swords which I suppose have been kept ready for many years for this purpose. He takes it and castrates himself and then runs wild through the city, bearing in his hands what he has cut off. He casts it into any house at will, and from this house he receives women’s raiment and ornaments. Thus they act during their ceremonies of castration.<br />
<br />
52. The Galli, when dead, are not buried like other men, but when a Gallus dies his companions carry him out into the suburbs, and laying him out on the bier on which they had carried him they cover him with stones, and after this return home. They wait then for seven days, after which they enter the temple. Should they enter before this they would be guilty of blasphemy.<br />
<br />
(There is a question whether this rite relates to Cybele and Attis, depending on whether we identify the Syrian goddess with Cybele.)<br />
<br />
==Hippolytus, 3rd century AD==<br />
<br />
[https://tertullian.org/fathers2/ANF-05/anf05-09.htm#P912_239623 Refutation of all heresies, book 5]. Includes two hymns to Attis.<br />
<br />
4. ... But they (the Naassenes) have these varied changes (of the soul) set down in the gospel inscribed "according to the Egyptians."22 They are, then, in doubt, as all the rest of men among the Gentiles, whether (the soul) is at all from something pre-existent, or whether from the self-produced (one),23 or from a widespread Chaos. And first they fly for refuge to the mysteries of the Assyrian...... an entity of this description the Assyrians call Adonis or Endymion;24 and when it is styled Adonis, Venus, he says, loves and desires the soul when styled by such a name. But Venus is production, according to them. But whenever Proserpine or Cora becomes enamoured with Adonis, there results, he says, a certain mortal soul separated from Venus (that is, from generation). But should the Moon pass into concupiscence for Endymion, and into love of her form, the nature,25 he says, of the higher beings requires a soul likewise. But if, he says, the mother of the gods emasculate Attis,26 and herself has this (person) as an object of affection, the blessed nature, he says, of the supernal and everlasting (beings) alone recalls the male power of the soul to itself.<br />
<br />
For (the Naassene) says, there is the hermaphrodite man. According to this account of theirs, the intercourse of woman with man is demonstrated, in conformity with such teaching, to be an exceedingly wicked and filthy (practice).27 For, says (the Naassene), Attis has been emasculated, that is, he has passed over from the earthly parts of the nether world to the everlasting substance above, where, he says, there is neither female or male,28 but a new creature,29 a new man, which is hermaphrodite. ...<br />
<br />
But they assert that not only is there in favour of their doctrine, testimony to be drawn from the mysteries of the Assyrians, but also from those of the Phrygians concerning the happy nature-concealed, and yet at the same time disclosed-of things that have been, and are coming into existence, and moreover will be,-(a happy nature) which, (the Naassene) says, is the kingdom of heaven to be sought for within a man.32 And concerning this (nature) they hand down an explicit passage, occurring33 in the Gospel inscribed according to Thomas,34 expressing themselves thus: "He who seeks me, will find me in children from seven years old; for there concealed, I shall in the fourteenth age be made manifest." This, however, is not (the teaching) of Christ, but of Hippocrates, who uses these words: "A child of seven years is half of a father." ...<br />
<br />
In this manner, (the Naassene) says, the knowledge of the Perfect Man is exceedingly profound, and difficult of comprehension. For, he says, the beginning of perfection is a knowledge of man, whereas knowledge of God is absolute perfection.<br />
<br />
The Phrygians, however, assert, he says, that he is likewise "a green ear of corn reaped." And after the Phrygians, the Athenians, while initiating people into the Eleusinian rites, likewise display to those who are being admitted to the highest grade at these mysteries, the mighty, and marvellous, and most perfect secret suitable for one initiated into the highest mystic truths: (I allude to) an ear of corn in silence reaped. But this ear of corn is also (considered) among the Athenians to constitute the perfect enormous illumination (that has descended) from the unportrayable one, just as the Hierophant himself (declares); not, indeed, emasculated like Attis,115 but made a eunuch by means of hemlock, and despising116 all carnal generation. ...<br />
<br />
They rashly assume in this manner, that whatsoever things have been said and done by all men, (may be made to harmonize) with their own particular mental view, alleging that all things become spiritual. Whence likewise they assert, that those exhibiting themselves in theatres,-not even these say or do anything without premeditation. Therefore, he (the Naassene) says, when, on the people assembling in the theatres, any one enters clad in a remarkable robe, carrying a harp and playing a tune (upon it, accompanying it) with a song of the great mysteries, he speaks as follows, not knowing what he says: "Whether (thou art) the race of Saturn or happy Jupiter,126 or mighty Rhea, Hail, Attis, gloomy mutilation of Rhea. Assyrians style thee thrice-longed-for Adonis, and the whole of Egypt (calls thee) Osiris, celestial horn of the moon; Greeks denominate (thee) Wisdom; Samothracians, venerable Adam; Haemonians, Corybas; and them Phrygians (name thee) at one time Papa, at another time Corpse, or God, or Fruitless, or Aipolos, or green Ear of Corn that has been reaped, or whom the very fertile Amygdalus produced-a man, a musician." This, he says, is multiform Attis, whom while they celebrate in a hymn, they utter these words: "I will hymn Attis, son of Rhea, not with the buzzing sounds of trumpets, or of Idaean pipers, which accord with (the voices of) the Curetes; but I will mingle (my song) with Apollo's music of harps, evoe, evan, ' inasmuch as thou art Pan, as thou art Bacchus, as thou art shepherd of brilliant stars."<br />
<br />
On account of these and such like reasons, these constantly attend the mysteries called those of the "Great Mother," supposing especially that they behold by means of the ceremonies performed there the entire mystery. For these have nothing more than the ceremonies that are performed there, except that they are not emasculated: they merely complete the work of the emasculated. For with the utmost severity and vigilance they enjoin (on their votaries) to abstain, as if they were emasculated, from intercourse with a woman. The rest, however, of the proceeding (observed in these mysteries), as we have declared at some length, (they follow) just as (if they were) emasculated persons. And they do not worship any other object but Naas, (from thence) being styled Naasseni. ...<br />
<br />
<br />
<br />
<br />
==Arnobius, 3-4th century AD==<br />
<br />
[http://www.tertullian.org/fathers2/ANF-06/anf06-138.htm#P7705_2431814 Arnobius the Elder, Against the Pagans, book 5, 5-7]:<br />
<br />
5. In Timotheus, who was no mean mythologist, and also in others equally well informed, the birth of the Great Mother of the gods, and the origin of her rites, are thus detailed, being derived-as he himself writes and suggests-from learned books of antiquities, and from his acquaintance with the most secret mysteries:-<br />
<br />
Within the confines of Phrygia, he says, there is a rock of unheard-of wildness in every respect, the name of which is Agdus, so named by the natives of that district. Stones taken from it, as Themis by her oracle had enjoined, Deucalion and Pyrrha threw upon the earth, at that time emptied of men; from which this Great Mother, too, as she is called, was fashioned along with the others, and animated by the deity. Her, given over to rest and sleep on the very summit of the rock, Jupiter assailed with lewdest desires. But when, after long strife, he could no accomplish what he had proposed to himself, he, baffled, spent his lust on the stone. This the rock received, and with many groanings Acdestis is born in the tenth month, being named from his mother rock.<br />
<br />
In him there had been resistless might, and a fierceness of disposition beyond control, a lust made furious, and derived from both sexes. He violently plundered and laid waste; he scattered destruction wherever the ferocity of his disposition had led him; he regarded not gods nor men, nor did he think anything more powerful than himself; he contemned earth, heaven, and the stars.<br />
<br />
6. Now, when it had been often considered in the councils of the gods, by what means it might be possible either to weaken or to curb his audacity, Liber, the rest hanging back, takes upon himself this task. With the strongest wine he drugs a spring much resorted to by Acdestis where he had been wont to assuage the heat and burning thirst roused in him by sport and hunting. Hither runs Acdestis to drink when he felt the need; he gulps down the draught too greedily into his gaping veins. Overcome by what he is quite unaccustomed to, he is in consequence sent fast asleep.<br />
<br />
Liber is near the snare which he had set; over his foot he throws one end of a halter formed of hairs, woven together very skilfully; with the other end he lays hold of his privy members. When the fumes of the wine passed off, Acdestis starts up furiously, and his foot dragging the noose, by his own strength he robs himself of his sex; with the tearing asunder of these parts there is an immense flow of blood; both are carried off and swallowed up by the earth; from them there suddenly springs up, covered with fruit, a pomegranate tree, seeing the beauty of which, with admiration, Nana, daughter of the king or river Sangarius, gathers and places in her bosom some of the fruit.<br />
<br />
By this she becomes pregnant; her father shuts her up, supposing that she had been debauched, and seeks to have her starved to death; she is kept alive by the mother of the gods with apples, and other food, and brings forth a child, but Sangarius orders it to be exposed.<br />
<br />
One Phorbas having found the child, takes it home, brings it up on goats’ milk; and as handsome fellows are so named in Lydia, or because the Phrygians in their own way of speaking call their goats attagi, it happened in consequence that the boy obtained the name Attis.<br />
<br />
Him the mother of the gods loved exceedingly, because he was of most surpassing beauty; and Acdestis, who was his companion, as he grew up fondling him, and bound to him by wicked compliance with his lust in the only way now possible, leading him through the wooded glades, and presenting him with the spoils of many wild beasts, which the boy Attis at first said boastfully were won by his own toil and labour. Afterwards, under the influence of wine, he admits that he is both loved by Acdestis, and honoured by him with the gifts brought from the forest; whence it is unlawful for those polluted by drinking wine to enter into his sanctuary, because it discovered his secret.<br />
<br />
7. Then Midas, king of Pessinus, wishing to withdraw the youth from so disgraceful an intimacy, resolves to give him his own daughter in marriage, and caused the gates of the town to be closed, that no one of evil omen might disturb their marriage joys.<br />
<br />
But the mother of the gods, knowing the fate of the youth, and that he would live among men in safety only so long as he was free from the ties of marriage, that no disaster might occur, enters the closed city, raising its walls with her head, which began to be crowned with towers in consequence. Acdestis, bursting with rage because of the boy’s being torn from himself, and brought to seek a wife, fills all the guests with frenzied madness: the Phrygians shriek aloud, panic-stricken at the appearance of the gods; a daughter of adulterous Gallus cuts off her breasts; Attis snatches the pipe borne by him who was goading them to frenzy; and he, too, now filled with furious passion, raving frantically and tossed about, throws himself down at last, and under a pine tree mutilates himself, saying, “Take these, Acdestis, for which you have stirred up so great and terribly perilous commotions.”<br />
<br />
With the streaming blood his life flies; but the Great Mother of the gods gathers the parts which had been cut off, and throws earth on them, having first covered them, and wrapped them in the garment of the dead. From the blood which had flowed springs a flower, the violet, and with this the tree is girt. Thence the custom began and arose, whereby you even now veil and wreath with flowers the sacred pine.<br />
<br />
The virgin who had been the bride, whose name, as Valerius the pontifex relates, was Ia, veils the breast of the lifeless youth with soft wool, sheds tears with Acdestis, and slays herself After her death her blood is changed into purple violets.<br />
<br />
The mother of the gods sheds tears also, from which springs an almond tree, signifying the bitterness of death. Then she bears away to her cave the pine tree, beneath which Attis had unmanned himself; and Acdestis joining in her wailings, she beats and wounds her breast, pacing round the trunk of the tree now at rest.<br />
<br />
Jupiter is begged by Acdestis that Attis may be restored to life: he does not permit it. What, however, fate allowed, he readily grants, that his body should not decay, that his hairs should always grow, that the least of his fingers should live, and should be kept ever in motion; content with which favours, it is said that Acdestis consecrated the body in Pessinus, and honoured it with yearly rites and priestly services.<br />
<br />
And:<br />
<br />
16. And yet how can you assert the falsehood of this story, when the very rites which you celebrate throughout the year testify that you believe these things to be true, and consider them perfectly trustworthy?<br />
<br />
For what is the meaning of that pine which on fixed days you always bring into the sanctuary of the mother of the gods? Is it not in imitation of that tree, beneath which the raging and ill-fated youth laid hands upon himself, and which the parent of the gods consecrated to relieve her sorrow?<br />
<br />
What mean the fleeces of wool with which you bind and surround the trunk of the tree? Is it not to recall the wools with which Ia covered the dying youth, and thought that she could procure some warmth for his limbs fast stiffening with cold? What mean the branches of the tree girt round and decked with wreaths of violets? Do they not mark this, how the Mother adorned with early flowers the pine which indicates and bears witness to the sad mishap?<br />
<br />
What mean the Galli with dishevelled hair beating their breasts with their palms? Do they not recall to memory those lamentations with which the tower-bearing Mother, along with the weeping Acdestis, wailing aloud, followed the boy? What means the abstinence from eating bread which you have named castus? Is it not in imitation of the time when the goddess abstained from Ceres’ fruit in her vehement sorrow?<br />
<br />
17. Or if the things which we say are not so declare, say yourselves-those effeminate and delicate men whom we see among you in the sacred rites of this deity-what business, what care, what concern have they there; and why do they like mourners wound their arms and breasts, and act as those dolefully circumstanced?<br />
<br />
What mean the wreaths, what the violets, what the swathings, the coverings of soft wools? Why, finally, is the very pine, but a little before swaying to and fro among the shrubs, an utterly inert log, set up in the temple of the Mother of the gods next, like some propitious and very venerable deity?<br />
<br />
For either this is the cause which we have found in your writings and treatises, and in that case it is clear that you do not celebrate divine rites, but give a representation of sad events; or if there is any other reason which the darkness of the mystery has withheld from us, even it also must be involved in the infamy of some shameful deed. For who would believe that there is any honour in that which the worthless Galli begin, effeminate debauchees complete?<br />
<br />
And ch. 39:<br />
<br />
39. Whence, then, do we prove that all these narratives are records of events? Froth the solemn rites and mysteries of initiation, it is clear, whether those which are celebrated at fixed times and on set days, or those which are taught secretly by the heathen without allowing the observance of their usages to be interrupted.<br />
<br />
For it is not to be believed that these have no origin, are practised without reason or meaning, and have no causes connected with their first beginnings. That pine which is regularly born into the sanctuary of the Great Mother, is it not in imitation of that tree beneath which Attis mutilated and unmanned himself, which also, they relate, the goddess consecrated to relieve her grief? That erecting of phalli and fascina, which Greece worships and celebrates in rites every year, does it not recall the deed by which Liber paid his debt?<br />
<br />
==Firmicus Maternus, ca. 350 AD==<br />
<br />
[http://www.roger-pearse.com/weblog/?p=1433 Firmicus Maternus, De errore profanum religionum, chap. 3]<br />
<br />
III. (1) The Phyrgians who live at Pessinus around the banks of the river Gallus, assign first place to the earth over the other elements, and this they profess (volunt) is the mother of all things. Then, so that they also might have for themselves an order of annual sacred events, they have consecrated the love affair of a rich women, their queen, who chose to punish tyrannically the scorn of an adolescent lover, with annual lamentations. And to satisfy the irate woman, or to find consolation for her remorse, he whom they had buried a little earlier, they claim that he had come back to life. And as the soul of the woman burned with the impatience of excessive love, they built temples to the dead youth. Then they profess that the priests appointed should undergo from themselves what the angry woman had done because of the injury to her scorned beauty. So in the annual sacred rites in honour of the earth the pomp of his funeral is organised, and when men are persuaded that they are honouring the earth, they are (in fact) venerating the death and funeral of a wretch.<br />
<br />
(2) Here also, most sacred emperors, in order to shield this error, they profess that these natural sacred rites are also arranged rationally. They profess that the earth loves its fruits, they profess that Attis is exactly this, which is born from fruits; however the punishment which he sustained, this they profess is what the reaper with his scythe does to the ripe fruits. They call it his death when the collected seeds are stored; life again, when the sown seeds sprout in the turning of the years.<br />
<br />
(3) I would like them now to reply to my inquiry, why have they associated this simple (story of) seed and fruit with a funeral, with death, with scorn, with punishment, with love? Was there not anything else that might be said? Was there not anything else that poor mortals might do in grateful thanks to the highest God for the crop? So that you can give thanks for the reborn crop, you howl; so that you rejoice, you weep. And you, when you see the true reason, you do not finally repent of doing this, but you do this, so that busyied with the turning seasons, you still flee from life, you pine for death.<br />
<br />
(4) Let them tell me, how it benefits the crop, that they renew their tears with yearly howlings, that they groan over the calamities of a reborn corpse, which they say is arranged for a natural reason. You mourn and you wail, and you cover your mourning with another excuse. The farmer knew when he could furrow the earth with a plow, when he could sow the furrows with grain, he knew when to gather the crop ripened by the heat of the sun, he knew when to tread out the dried crop. This is the natural reason, these are the true sacrificial rites, which are carried out by the yearly labour in men of healthy minds. The divinity asks for this simplicity, that men should follow the laws ordained of the seasons (temporum) in collecting crops. Why do they try to explain this order by wretched fictions of a death? Why is that shielded with tears, which does not need to be shielded? From which let them admit of necessity, that these rites are not held in honour of the crops, but in honour of an unworthy death.<br />
<br />
(5) When they say that the earth is the mother of all the gods, and they allot the chief roles to this element, indeed it is mother of their gods, — this we don’t deny or refuse, because from it they are always making their bunch of gods, whether of stone or wood. The sea flows around the whole earth, and again it is held tight by the circle of the encircling embracing Ocean. The heavens also are covered by the lofty dome, blown through by winds, splashed by rains, and in fear, as shown by tremors of unremitting motion. What remains to you, who cultivate these things, consider; when your gods reveal their weakness to you in daily declarations.<br />
<br />
And chapter 27, 1 (ACW p.104)<br />
<br />
Ch. 27] The accursed butcher schemed (oh the wickedness of it!) to have his cult always renewed by something wooden, because he foreknew that man's life, once nailed to the wood of the cross, would thereby be clasped in the embrace of everlasting immortality, and he wanted to fool doomed men by a counterfeit of the wood. In the Phrygian cult of her whom they call the Mother of the Gods, a pine tree is cut every year, and an image of a youth is fastened on the middle of the tree. In the cult of Isis the trunk of a pine tree is cut away. Its center is skilfully hollowed out, and an effigy of Osiris made of seeds is buried there. In the cult of Proserpina a tree is felled and shaped into the form and look of a virgin, and when it has been carried into the city there is mourning for forty nights and on the fortieth night it is burned. But a similar fire consumes also those other wooden things which I have mentioned, for after a year flames devour a pyre made precisely of these wooden objects. Unhappy man! You are wrong and emphatically wrong. That fire will not be able to do you any good. Vainly you flatter yourself about these flames; vainly you always renew the fire with your fablings. The fire which exacts the penalty for your misdeeds rages in a continuation of torment forever.<br />
<br />
==Julian the Apostate, 363 AD==<br />
<br />
[http://www.tertullian.org/fathers2/NPNF1-02/npnf1-02-12.htm#P1101_586858 Julian, Oratio 5: on the Magna Mater]:<br />
<br />
Who then is the Mother of the Gods? She is the Source of the Intelligible and Creative Powers, which direct the visible ones; she that gave birth to and copulated with the mighty Jupiter: she that exists as a great goddess next to the Great One, and in union with the Great Creator; she that is dispenser of all life; cause of all birth; most easily accomplishing all that is made; generating without passion; creating all that exists in concert with the Father; herself a virgin, without mother, sharing the throne of Jupiter, the mother in very truth of all the gods; for by receiving within herself the causes of all the intelligible deities that be above the world, she became the source to things the objects of intellect.<br />
<br />
Now this goddess, who is also the same as Providence, was seized with a love without passion for Attis. … And this the legend aims at teaching when it makes the Mother of the Gods enjoin upon Attis to be her servant, and not to stray from her, and not fall in love with another woman. But he went forward, and descended as far as the boundaries of Matter.<br />
<br />
But when it became necessary for this ignorance to cease and be stopped—-then Corybas, the mighty Sun, the colleague of the Mother of the Gods … persuades the lion to turn informer. Who then is this lion? We hear him styled “blazing”—-he must, therefore, I think, be the cause presiding over the hot and fiery element; that which was about to wage war against the Nymph, and to make her jealous of her intercourse with Attis; and who this Nymph is we have already stated.<br />
<br />
This lion, the fable tells, lent his aid to the Mother of the Gods … and by his detecting the offence and turning informer, became the author of the castration of the youth. … not without the intervention of the fabled madness of Attis…<br />
<br />
It is not therefore unreasonable to suppose this Attis a sixper-natural personage (in fact the fable implies as much), or rather in all respects, a deity, seeing that he comes forth out of the Third Creator, and returns again after his castration, to the Mother of the Gods… the fable styles him a “demi-god,” … The Corybantes… are assigned by the Great Mother to act as his bodyguard…<br />
<br />
This great god of ours is Attis; this is the meaning of the “Flight of King Attis” that we have just been lamenting; his “Concealments,” his “Vanishings,” his “Descents into the Cave.” Let my evidence be the time of year when all these ceremonies take place; for it is said that the Sacred Tree is cut down at the moment when the Sun arrives at the extreme point of the equinoctial arc: next in order follows the Sounding of the trumpets, and lastly is cut down the sacred and ineffable Harvest of the god Gallos: after these come, as they say, the Hilaria and festivities.<br />
<br />
Now that a “cessation of Indefinity” is meant by the castration so much talked of by the vulgar, is self-evident from the fact that when the Sun touches the equinoctial circle, where that which is most definite is placed (for equality is definite, but inequality indefinite and inexplicable); at that very moment (according to the report), the Sacred Tree is cut down; then come the other rites in their order; whereof some are done in compliance with rules that be holy and not to be divulged; others for reasons allowable to be discussed.<br />
<br />
The “Cutting of the Tree;” this part refers to the legend about the Gallos, and has nothing to do with the rites which it accompanies… The rite, therefore, enjoins upon us who are celestial by our nature, but who have been carried down to earth, to reap virtue joined with piety from our conduct upon earth, and to aspire upwards unto the deity, the primal source of being and the fount of life. Then immediately after the cutting does the trumpet give out the invocation to Attis and to those that be of heaven, whence we took our flight, and fell down to earth.<br />
<br />
And after this, when King Attis checks the Indefinity by the means of castration, the gods thereby warn us to extirpate in ourselves all incontinence, and to imitate the example, and to run upwards unto the Definite, and the Uniform, and if it be possible, to the One itself; which being accomplished the “Hilaria” must by all means follow. For what could be more contented, what more hilarious than the soul that has escaped from uncertainty, and generation, and the tumult that reigns therein, and hastens upwards to the gods? Of whose number was this Attis, whom the Mother of the Gods would not suffer to advance farther than was proper for him, but turned him towards herself, and enjoined him to check all indefinity.<br />
<br />
==Sallustius, mid-4th century AD==<br />
<br />
[http://www.sacred-texts.com/cla/fsgr/fsgr10.htm Sallustius, ''De diis et mundo''] - This is the Gilbert Murray 1925 translation, published as an appendix to "Five stages of Greek religion" and appearing on Sacred Texts. There is also an A.D.Nock 1926 translation, and there is an old one somewhere by Thomas Taylor. Sallustius was a friend of Julian the Apostate.<br />
<br />
To take another myth, they say that the Mother of the Gods seeing Attis lying by the river Gallus fell in love with him, took him, crowned him with her cap of stars, and thereafter kept him with her. He fell in love with a nymph and left the Mother to live with her. For this the Mother of the Gods made Attis go mad and cut off his genital organs and leave them with the nymph, and then return and dwell with her.<br />
<br />
Now the Mother of the Gods is the principle that generates life; that is why she is called Mother. Attis is the creator of all things which are born and die; that is why he is said to have been found by the river Gallus. For Gallus signifies the Galaxy, or Milky Way, the point at which body subject to passion begins. Now as the primary gods make perfect the secondary, the Mother loves Attis and gives him celestial powers.<br />
<br />
That is what the cap means. Attis loves a nymph: the nymphs preside over generation, since all that is generated is fluid. But since the process of generation must be stopped somewhere, and not allowed to generate something worse than the worst, the creator who makes these things casts away his generative powers into the creation and is joined to the Gods again. Now these things never happened, but always are. And mind sees all things at once, but reason (or speech) expresses some first and others after. Thus, as the myth is in accord with the cosmos, we for that reason keep a festival imitating the cosmos, for how could we attain higher order?<br />
<br />
==Anonymous, Carmen Ad Antonium, early 5th century (?)==<br />
<br />
[http://www.roger-pearse.com/weblog/?p=4402 here].<br />
<br />
Why do they hope for anything from Jupiter who came second after this king yet who is served with offerings through the lips of suppliants? This god has a mother, too, who was overtaken by love for a shepherd, so the shepherd himself came before Jupiter or Jove; but the shepherd was his superior for, wishing to preserve his chastity, he rejected the goddess who in her rage castrated him so that he who had refused to come to her bed should never be the husband of another. Was this the just ordinance of the gods however, that a man who had not been made a fornicator should never be a husband? Now, too, eunuchs chant shameful mysteries nor are there lacking men to be corrupted by this infection. They worship some secret the more profound for being behind closed doors and call holy something which would render a modest man unholy should he approach it. Thus the priest himself, more restricted, avoids sleeping with women and accepts the embrace of men.<br />
<br />
==Augustine, early 5th century AD==<br />
<br />
[http://www.tertullian.org/fathers2/NPNF1-02/npnf1-02-12.htm#P1101_586858 Augustine, City of God, book 6, chapter 7]:<br />
<br />
There are sacred rites of the mother of the gods, in which the beautiful youth Atys, loved by her, and castrated by her through a woman’s jealousy, is deplored by men who have suffered the like calamity, whom they call Galli. …<br />
<br />
What good is to be thought of their sacred rites which are concealed in darkness, when those which are brought forth into the light are so detestable? And certainly they themselves have seen what they transact in secret through the agency of mutilated and effeminate men. Yet they have not been able to conceal those same men miserably and vile enervated and corrupted.<br />
<br />
Let them persuade whom they can that they transact anything holy through such men, who, they cannot deny, are numbered, and live among their sacred things. We know not what they transact, but we know through whom they transact; for we know what things are transacted on the stage, where never, even in a chorus of harlots, hath one who is mutilated or an effeminate appeared.<br />
<br />
And, nevertheless, even these things are acted by vile and infamous characters; for, indeed, they ought not to be acted by men of good character. What, then, are those sacred rites, for the performance of which holiness has chosen such men as not even the obscenity of the stage has admitted?<br />
<br />
==Proclus, 5th century==<br />
<br />
[http://www.tertullian.org/fathers/marinus_01_life_of_proclus.htm Marinus, Life of Proclus, ch. 33]<br />
<br />
33. But if I was to enumerate all the facts of this kind, and to report the particular devotion which he held for Pan, son of Hermes, the great favors he received, and the numerous times he was, in Athens, saved by intervention of the divinity, and to relate in detail the protections and the advantages he received from the Mother of the Gods, of which he was particularly proud and happy, I would no doubt seem chattering vainly, to those who may light on this book by chance, and some may even think I am saying things little worthy of belief. For there were a considerable number of episodes, that were of almost daily occurrence, when this goddess [Cybele] spoke or acted in his favor; and their number and character are so unusual that I myself do not have their exact and precise memory.<br />
<br />
If anyone desires to know with what favor he was attached to this goddess, let him read Proclus's book on the Mother of the Gods, and it will be seen that with inspiration from on high he has been able to expound the whole theology relative to the goddess, and to explain philosophically all that the liturgical actions and the oral instructions mythically teach us about the goddess, and Attis, so that they will no longer be troubled by those seemingly absurd lamentations [for Attis] and all the secret traditions related in her ceremonies.<br />
<br />
==Damascius, early 6th century AD==<br />
<br />
From ''Life of Isidore'', as quoted by Photius, ''Bibliotheca'', codex 242.<br />
<br />
131. At Hierapolis in Phrygia there is a temple of Apollo and under the temple a subterranean fissue descends, which exhales lethal vapours. It is impossible to pass this gulf without danger, even for birds, and everyone who enters it dies. But the author says that it is possible for initiates to descend into the crevasse itself and stay there without injury. The author says that he himself and the philosopher Dorus, led by curiosity, descended into it and returned unharmed. The author says, “I then slept at Hierapolis and in a dream it seemed to me that I was Attis and that, by the order of the Great Mother of the gods, I was celebrating what is called the festival of the Hilaria; this dream signified our liberation from Hades. On returning to Aphrodisias, I recounted to Asclepiodotus the vision that I had in the dream. And he, full of admiration for what had happened to me, recounted to me, not “a dream for a dream”, but a great marvel in exchange for a little one.<br />
<br />
He said in fact that in his youth he had gone to that place to study the nature of it. He had rolled his mantle two and three times around his nostrils so that in the event of frequent fumes, he could breathe not the poisoned and deleterious air but pure and safe air which he had brought with him captured in his mantle. Proceeding thus, he entered on the descent, following a current of hot water which came out from there, and ran the length of the inaccessible crevasse. All the same he didn’t get to the bottom of the descent, because the access to it was cut off by the abundance of water and the passage was impossible to an ordinary man, but the one descending, possessed by the divinity, was carried to the bottom. Asclepiodotus then climbed back up from that place without injury thanks to his ingenuity. Later he even tried to recreate the lethal air using various ingredients.<br />
<br />
== John the Lydian ==<br />
<br />
''De Mensibus'' IV.41 reads:<br />
<br />
On day 11, the kalends of April, a pine tree is carried into the Palatine by the tree-bearers. But the emperor Claudius instituted these these ferias, a man of such justice in judgement that...<br />
<br />
=Inscriptions=<br />
<br />
The Clauss-Slaby database records a considerable number of inscriptions that mention Attis.<br />
<br />
==Attis Menotyrannus==<br />
<br />
In the following inscriptions, all from Rome and nowhere else, Attis is labelled "Menotyrannus". This may mean "Lord of the months", or derive from Men, the Phygian moon-god.<br />
<br />
Publication: CIL 06, 00499 p 3005, 3757 = CIL 06, 30779c = D 04147 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae Summae Parenti Hermae et Attidi Menotyranno Invicto Clodius Hermogenianus Caesarius vir clarissimus proconsul Africae praefectus urbis Romae XV vir sacris faciundis taurobolio criobolioque perfecto XIIII Kalendas Augustas diis animae suae mentisque custodibus aram dicavit domino nostro Gratiano Augusto tertium et 3 Aequitio conssulibus<br />
<br />
Publication: CIL 06, 00500 p 3005, 3757 = CIL 06, 30779d = D 04148 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno Conservatoribus suis Caelius Hilarianus vir clarissimus duodecimvir urbis Romae pater sacrorum et hieroceryx Invicti Mithrae sacerdos dei Liberi sacerdos deae Hecate domino nostro Gratiano Augusto et Merobaude conssulibus III Idus Maias<br />
<br />
Publication: CIL 06, 00501 p 3005, 3757 = CIL 06, 30779e = D 04149 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Sancto Menotyranno Quintus Clodius Flavianus vir clarissimus pontifex maior XV vir sacris faciundis septemvir epulonum pontifex dei Solis taurobolio criobolioque percepto aram dicavit Nonis Aprilibus FFllavis Merobaude II et Saturnino conssulibus<br />
<br />
Publication: CIL 06, 00508 p 3757 = D 04146 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Potentissimis Dis Matri deum Magnae et Attidi Menotyranno 3 Serapias honesta femina sacrata deum matris et Proserpinae taurobolium criobolium caernophorum perceptum per Flavium Antonium Eustochium sacerdotem Phryges maximus praesentibus et tradentibus cclarissimorum vvirorum ex amplissimo et sanctissimo collegio XV virum sacris faciundis die XIII Kalendas Maias cerealibus ddominis nnostris Constantino Maximo Augusto V et Licinio Iuniori Caesari conssulibus<br />
<br />
Publication: CIL 06, 00511 p 3005 = CLE 01529 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menoturano sacrum nobilis in causis forma celsusque Sabinus hic pater Invicti mystica victor habet sermo duos 3 reservans consimiles aufert3 et veneranda movet Cibeles Triodeia signa augentur meritis simbola tauroboli Rufius Caeionius Caeioni(?) Sabini filius(?) vir classimus pontifex maior hierofanta deae Hecatae augur publicus populi Romani Quiritium pater sacrorum Invicti Mthrae tauroboliatus Matris deum Magnae Idaeae et Attidis Minoturani et aram IIII Idus Martias Gratiano V et Merobaude consulibus dedicabit antiqua generose domo cui regia Vesta pontifici felix sacrato militat igne idem augur triplicis cultor venerande Dianae Persidicique Mithrae antistes Babloniae templi taurobolique simul magni dux mistice sacri<br />
<br />
Publication: AE 1953, 00238 = AE 2000, +00136 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Idaeae et Attidi sancto Menotyranno Alfenius Ceionius Iulianus Kamenius vir clarissimus VII vir epulonum pater et hieroceryx sacrorum Soli Invicti Mithrae hierofanta H{a}ecatae archibucolus dei liberi aram taurobolio criobolioque percepto dicabit! die XIIII Kalendas Augustas domino nostro Gratiano Augusto III et Equitio conssulibus<br />
<br />
Publication: CIL 06, 00512 p 3005, 3757 = CLE +00264 = D 04154 = SIRIS 00447 = RICIS-02, 005010212 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno dis Magnis et Tutatoribus suis Ceionius Rufius Volusianus vir clarissimus et inlustris ex vicario Asiae et Ceioni Rufi Volusiani viri clarissimi et inlustris ex praefecto praetorio et ex praefecto urbi et Caecinae Lollianae clarissimae et inlustris feminae deae Isidis sacerdotis filius iterato viginti annis expletis taurobolii sui aram constituit et consecravit X Kalendas Iunias domino nostro Valentiniano Augusto IIII et Neoterio conssulibus<br />
<br />
Publication: AE 1953, 00237 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Magnae Idaeae et Attidi Menotyranno Sextius Rusticus vir clarissimus et inlustris pater patrum dei Invicti Mithrae<br />
<br />
Publication: AE 1953, 00238 = AE 2000, +00136 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Idaeae et Attidi sancto Menotyranno Alfenius Ceionius Iulianus Kamenius vir clarissimus VII vir epulonum pater et hieroceryx sacrorum Soli Invicti Mithrae hierofanta Haecatae archibucolus dei liberi aram taurobolio criobolioque percepto dicabit! die XIIII Kalendas Augustas domino nostro Gratiano Augusto III et Equitio conssulibus<br />
<br />
Publication: CIL 06, 00499 p 3005, 3757 = CIL 06, 30779c = D 04147 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae Summae Parenti Hermae et Attidi Menotyranno Invicto Clodius Hermogenianus Caesarius vir clarissimus proconsul Africae praefectus urbis Romae XV vir sacris faciundis taurobolio criobolioque perfecto XIIII Kalendas Augustas diis animae suae mentisque custodibus aram dicavit domino nostro Gratiano Augusto tertium et 3 Aequitio conssulibus<br />
<br />
Publication: CIL 06, 00500 p 3005, 3757 = CIL 06, 30779d = D 04148 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno Conservatoribus suis Caelius Hilarianus vir clarissimus duodecimvir urbis Romae pater sacrorum et hieroceryx Invicti Mithrae sacerdos dei Liberi sacerdos deae Hecate domino nostro Gratiano Augusto et Merobaude conssulibus III Idus Maias<br />
<br />
Publication: CIL 06, 00501 p 3005, 3757 = CIL 06, 30779e = D 04149 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Sancto Menotyranno Quintus Clodius Flavianus vir clarissimus pontifex maior XVvir sacris faciundis septemvir epulonum pontifex dei Solis taurobolio criobolioque percepto aram dicavit Nonis Aprilibus FFllavis Merobaude II et Saturnino conssulibus<br />
<br />
Publication: CIL 06, 00508 p 3757 = D 04146 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Potentissimis Dis Matri deum Magnae et Attidi Menotyranno 3 Serapias honesta femina sacrata deum matris et Proserpinae taurobolium criobolium caernophorum perceptum per Flavium Antonium Eustochium sacerdotem Phryges maximus praesentibus et tradentibus cclarissimorum vvirorum ex amplissimo et sanctissimo collegio XV virum sacris faciundis die XIII Kalendas Maias cerealibus ddominis nnostris Constantino Maximo Augusto V et Licinio Iuniori Caesari conssulibus<br />
<br />
Publication: CIL 06, 00511 p 3005 = CLE 01529 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menoturano sacrum nobilis in causis forma celsusque Sabinus hic pater Invicti mystica victor habet sermo duos 3 reservans consimiles aufert et veneranda movet Cibeles Triodeia signa augentur meritis simbola tauroboli Rufius Caeionius Caeioni(?) Sabini filius(?) vir classimus pontifex maior hierofanta deae Hecatae augur publicus populi Romani Quiritium pater sacrorum Invicti Mthrae tauroboliatus Matris deum Magnae Idaeae et Attidis Minoturani et aram IIII Idus Martias Gratiano V et Merobaude consulibus dedicabit antiqua generose domo cui regia Vesta pontifici felix sacrato militat igne idem augur triplicis cultor venerande Dianae Persidicique Mithrae antistes Babloniae templi taurobolique simul magni dux mistice sacri<br />
<br />
Publication: CIL 06, 00512 p 3005, 3757 = CLE +00264 = D 04154 = SIRIS 00447 = RICIS-02, 005010212 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno dis Magnis et Tutatoribus suis Ceionius Rufius Volusianus vir clarissimus et inlustris ex vicario Asiae et Ceioni Rufi Volusiani viri clarissimi et inlustris ex praefecto praetorio et ex praefecto urbi et Caecinae Lollianae clarissimae et inlustris feminae deae Isidis sacerdotis filius iterato viginti annis expletis taurobolii sui aram constituit et consecravit X Kalendas Iunias domino nostro Valentiniano Augusto IIII et Neoterio conssulibus</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/Attis_Sources&diff=3057User:Roger Pearse/Attis Sources2022-02-10T16:18:04Z<p>Roger Pearse: /* Firmicus Maternus, ca. 350 AD */</p>
<hr />
<div>These are the sources for our knowledge of Attis.<br />
<br />
=Literary Sources=<br />
<br />
==Herodotus, 5th century BC==<br />
<br />
In [http://www.sacred-texts.com/cla/hh/hh1030.htm Herodotus, book 1, 34-45], there is a rambling story about Atys, son of Croesus, accidentally killed by a spear while hunting. In his Cybele and Attis, M. J. Vermaseren considers whether this is part of the myth of Attis. [http://www.dur.ac.uk/Classics/histos/1998/lewis.html This link] asserts that it is.<br />
<br />
But on looking at the text, the account is very dissimilar from any other account. Does anything but the similarity of name tie the two together?<br />
<br />
==Catullus, 84 BC – ca. 54 BC==<br />
<br />
[http://www.vroma.org/~hwalker/VRomaCatullus/063.html Catullus, Poem 63]:<br />
<br />
<pre><br />
Borne in his swift bark over deep seas,<br />
Attis, when eagerly with speedy foot he reached the Phrygian woodland,<br />
and entered the goddess’ abodes, shadowy, forest-crowned;<br />
there, goaded by raging madness, bewildered in mind,<br />
he cast down from him with sharp flint-stone the burden of his member.<br />
So when she felt her limbs to have lost their manbood,<br />
still with fresh blood dabbling the face of the ground,<br />
swiftly with snowy bands she seized the light timbrel,<br />
your timbrel, Cybele, thy mysteries, Mother,<br />
and shaking with soft fingers the hollow oxhide<br />
thus began she to sing to her companions tremulously:<br />
“Come away, ye Gallae, go to the mountain forests of Cybele together,<br />
together go, wandering herd of the lady of Dindymus,<br />
who swiftly seeking alien homes as exiles,<br />
followed my rule as I led you in my train,<br />
endured the fast-flowing brine and the savage seas,<br />
and unmanned your bodies from utter abhorrence of love,<br />
cheer ye your Lady’s heart with swift wanderings.<br />
Let dull delay depart from your mind; go together, follow<br />
to the Phrygian house of Cybele, to the Phrygian forests of the goddess,<br />
where the noise of cymbals sounds, where timbrels re-echo,<br />
where the Phrygian flute-player blows a deep note on his curved reed,<br />
where the Maenads ivy-crowned toss their heads violently,<br />
where with shrill yells they shake the holy emblems,<br />
where that wandering company of the goddess is wont to rove,<br />
whither for us ’tis meet to hasten with rapid dances.”<br />
So soon as Attis, woman yet no true one, chanted thus to her companions,<br />
the revellers suddenly with quivering tongues yell aloud,<br />
the light timbrel rings again, clash again the hollow cymbals,<br />
swiftly to green Ida goes the rout with hurrying foot.<br />
Then too frenzied, panting, uncertain, wanders, gasping for breath,<br />
attended by the timbrel, Attis, through the dark forests their leader,<br />
as a heifer unbroken starting aside from the burden of the yoke.<br />
Fast follow the Gallae their swift-footed leader.<br />
So when they gained the house of Cybele, faint and weary,<br />
after much toil they take their rest without bread;<br />
heavy sleep covers their eyes with drooping weariness,<br />
the delirious madness of their mind departs in soft slumber.<br />
But when the sun with the flashing eyes of his golden face<br />
lightened the clear heaven, the firm lands, the wild sea,<br />
and chased away the shades of night with eager tramping steeds refreshed,<br />
then Sleep fled from wakened Attis and quickly was gone;<br />
him the goddess Pasithea received in her fluttering bosom.<br />
So after soft slumber, freed from violent madness,<br />
as soon as Attis himself in his heart reviewed his own deed,<br />
and saw with clear mind what lie had lost and where he was,<br />
with surging mind again he sped back to the waves.<br />
There, looking out upon the waste seas with streaming eyes,<br />
thus did she piteously address her country with tearful voice:<br />
” O my country that gavest me life! O my country that barest me!<br />
leaving whom, all wretch! as runaway servants leave their masters,<br />
I have borne my foot to the forests of Ida,<br />
to live among snows and frozen lairs of wild beasts,<br />
and visit in my frenzy all their lurking-dens,<br />
– where then or in what region do I think thy place to be, O my country?<br />
Mine eyeballs unbidden long to turn their gaze to thee<br />
while for a short space my mind is free from wild frenzy.<br />
I, shall I from my own home be borne far away into these forests?<br />
from my country, my possessions, my friends, my parents, shall I be?<br />
absent from the market, the wrestling-place, the racecourse, the playground?<br />
unhappy, all unhappy heart, again, again must thou complain.<br />
For what form of human figure is there which I had not?<br />
I, to be a woman–who was a stripling, I a youth, I a boy,<br />
I was the flower of the playground, I was once the glory of the palaestra:<br />
mine were the crowded doorways, mine the warm thresholds,<br />
mine the flowery garlands to deck my house<br />
when I was to leave my chamber at sunrise.<br />
I, shall I now be called–what? a handmaid of the gods, a ministress of Cybele?<br />
I a Maenad, I part of myself, a barren man shall I be?<br />
I, shall I dwell in icy snow-clad regions of verdant Ida,<br />
I pass my life under the high summits of Phrygia,<br />
with the hind that haunts the woodland, with the boar that ranges the forest?<br />
now, now I rue my deed, now, now I would it were undone.”<br />
From his rosy lips as these words issued forth,<br />
bringing a new message to both ears of the gods,<br />
then Cybele, loosening the fastened yoke from her lions,<br />
and goading that foe of the herd who drew on the left, thus speaks:<br />
“Come now,” she says, “come, go fiercely, let madness hunt him hence<br />
bid him hence by stroke of madness hie him to the forests again,<br />
him who would be too free, and run away from my sovereignty.<br />
Come, lash back with tail, endure thy own scourging,<br />
make all around resound with bellowing roar,<br />
shake fiercely on brawny neck thy ruddy mane.”<br />
Thus says wrathful Cybele, and with her hand unbinds the yoke.<br />
The monster stirs his courage and rouses him to fury of heart;<br />
he speeds away, he roars, with ranging foot he breaks the brushwood.<br />
But when he came to the watery stretches of the white-gleaming shore,<br />
and saw tender Attis by the smooth spaces of the sea,<br />
he rushes at him–madly flies Attis to the wild woodland.<br />
There always for all his lifetime was he a handmaid.<br />
Goddess, great goddess, Cybele, goddess, lady of Dindymus<br />
far from my house be all thy fury, O my queen<br />
others drive thou in frenzy, others drive thou to madness.<br />
</pre><br />
<br />
==Diodorus Siculus, 1st century BC==<br />
<br />
[http://penelope.uchicago.edu/Thayer/E/Roman/Texts/Diodorus_Siculus/3D*.html Diodorus Siculus, History, 3.58.4-59.1]:<br />
<br />
58. However, an account is handed down also that this goddess was born in Phrygia. For the natives of that country have the following myth: In ancient times Meïon became king of Phrygia and Lydia; and marrying Dindymê he begat an infant daughter, but being unwilling to rear her he exposed her on the mountain which was called Cybelus. There, in accordance with some divine providence, both the leopards and some of the other especially ferocious wild beasts offered their nipples to the child and so gave it nourishment, and some women who were tending the flocks in that place witnessed the happening, and being astonished at the strange event took up the babe and called her Cybelê after the name of the place. The child, as she grew up, excelled in both beauty and virtue and also came to be admired for her intelligence; for she was the first to devise the pipe of many reeds and to invent cymbals and kettledrums with which to accompany the games and the dance, and in addition she taught how to heal the sicknesses of both flocks and little children by means of rites of purification; in consequence, since the babes were saved from death by her spells and were generally taken up in her arms, her devotion to them and affection for them led all the people to speak of her as the “mother of the mountain.” The man who associated with her and loved her more than anyone else, they say, was Marsyas the physician, who was admired for his intelligence and chastity; and a proof of his intelligence they find in the fact that he imitated the sounds made by the pipe of many reeds and carried all its notes over into the flute, and as an indication of his chastity they cite his abstinence from sexual pleasures until the day of his death.<br />
<br />
Now Cybelê, the myth records, having arrived at full womanhood, came to love a certain native youth who was known as Attis, but at a later time received the appellation Papas; with him she consorted secretly and became with child, and at about the same time her parents recognized her as their child. Consequently she was brought up into the palace, and her father welcomed her at the outset under the impression the she was a virgin, but later, when he learned of her seduction, he put to death her nurses and Attis as well and cast their bodies forth to lie unburied; whereupon Cybelê, they say, because of her love for the youth and grief over the nurses, became frenzied and rushed out of the palace into the countryside. And crying aloud and beating upon a kettledrum she visited every country alone, with hair hanging free, and Marsyas, out of pity for her plight, voluntarily followed her and accompanied her in her wanderings because of the love which he had formerly borne her. … And Apollo, they say, laid away both the lyre and the pipes as a votive offering in the cave of Dionysus, and becoming enamoured of Cybelê joined in her wanderings as far as the land of the Hyperboreans.<br />
<br />
But, the myth goes on to say, a pestilence fell upon human beings throughout Phrygia and the land ceased to bear fruit, and when the unfortunate people inquired of the god how they might rid themselves of their ills he commanded them, it is said, to bury the body of Attis and to honour Cybelê as a goddess. Consequently the physicians, since the body had disappeared in the course of time, made an image of the youth, before which they sang dirges and by means of honours in keeping with his suffering propitiated the wrath of him who had been wronged; and these rites they continue to perform down to our own lifetime. As for Cybelê, in ancient times they erected altars and performed sacrifices to her yearly; and later they built for her a costly temple in Pisinus of Phrygia, and established honours and sacrifices of the greatest magnificence, Midas their king taking part in all these works out of his devotion to beauty; and beside the statue of the goddess they set up panthers and lions, since it was the common opinion that she had first been nursed by these animals.<br />
<br />
Such, then, are the myths which are told about Mother of the God both among the Phrygians and by the Atlantians who dwell on the coast of the ocean.<br />
<br />
==Ovid, 1st century AD==<br />
<br />
[http://www.tkline.freeserve.co.uk/OvidFastiBkFour.htm Ovid, Fasti, 4.221-224]:<br />
<br />
<pre><br />
… I said ‘Where did this urge to cut off<br />
Their members come from?’ As I ended, the Muse spoke:<br />
‘In the woods, a Phrygian boy, Attis, of handsome face,<br />
Won the tower-bearing goddess with his chaste passion.<br />
She desired him to serve her, and protect her temple,<br />
And said: “Wish, you might be a boy for ever.”<br />
He promised to be true, and said: “If I’m lying<br />
May the love I fail in be my last love.”<br />
He did fail, and in meeting the nymph Sagaritis,<br />
Abandoned what he was: the goddess, angered, avenged it.<br />
She destroyed the Naiad, by wounding a tree,<br />
Since the tree contained the Naiad’s fate.<br />
Attis was maddened, and thinking his chamber’s roof<br />
Was falling, fled for the summit of Mount Dindymus.<br />
Now he cried: “Remove the torches”, now he cried:<br />
“Take the whips away”: often swearing he saw the Furies.<br />
He tore at his body too with a sharp stone,<br />
And dragged his long hair in the filthy dust,<br />
Shouting: “I deserved this! I pay the due penalty<br />
In blood! Ah! Let the parts that harmed me, perish!<br />
Let them perish!” cutting away the burden of his groin,<br />
And suddenly bereft of every mark of manhood.<br />
His madness set a precedent, and his unmanly servants<br />
Toss their hair, and cut off their members as if worthless.’<br />
So the Aonian Muse, eloquently answering the question<br />
I’d asked her, regarding the causes of their madness.<br />
</pre><br />
<br />
[https://ovid.lib.virginia.edu/trans/Metamorph10.htm#484521419 Ovid, Metamorphoses (X.103-5)]:<br />
<br />
You came, also, ... the pliant palms, the winner’s prize; and you, the shaggy-topped pine tree, armed with needles, sacred to Cybele, mother of the gods, since Attis exchanged his human form for you, and hardened in your trunk.<br />
<br />
==Pausanias, 2nd century AD==<br />
<br />
[http://books.google.co.uk/books?dq=pausanias+description+of+greece&pg=PA191&id=p6oAAAAAYAAJ&ots=mmAB61GsT0 Pausanius, Guide to Greece, 7.17.5]:<br />
<br />
The Achaian city Dyme is distant about four hundred stadia from Larissus… Besides this the Dymaei have a temple of Minerva, and a statue of the goddess, which is very ancient. They have also another temple sacred to the mother Dindymene, and Attes. But who Attes is, I have not been able to discover, because it is. an arcane affair. Hermesianax, indeed, a writer of elegies, says, that he was the son of the Phrygian Calaus, and that he was produced by his mother incapable of begetting children. That when he arrived at manhood he migrated to Lydia, and established there the orgies of the Great Mother. And that he was so highly honoured by the goddess, that it excited the indignation of Jupiter, who sent a boar into the Lydian fields, by which other Lydians were destroyed, and Attes himself was slain. The Gauls who inhabit Pesinus, confirm by their conduct the truth of this relation, for they cannot bear to touch swine. However, they report things concerning Attes far different from the above.<br />
<br />
Jupiter, say they, while he was asleep emitted his seed on the earth; this in process of time produced a daemon with twofold private parts, viz. with the parts of man and woman united. The name of this daemon was Agdistis: and the gods, in consequence of being terrified at him, cut off his virile parts. From these parts an almond tree was produced, the fruit of which, when ripe, the daughter of the river Sangarius gathered and concealed in her bosom. The fruit, however, immediately vanished, and she became pregnant. As the result of her pregnancy, she was delivered of a boy, who being left in the woods was educated by a goat, and who, as he grew in years, possessed a beauty surpassing that of the human form, and through which Agdistis fell in love with him. But when he arrived at manhood, his friends sent him to Pesinus, in order that he might marry the daughter of the king. Here, as they were singing the nuptial song, Agdistis presented himself before them, and Attes becoming insane, cut off his private parts. The king’s daughter, too, that was given to Attes, cut off her privities. But Agdistis was grieved that Attes had acted in this manner, and obtained of Jupiter that no part of the body of Attes should either become putrid or waste away. And such are the particulars which are reported about Attes.<br />
<br />
==Lucian, 2nd century AD==<br />
<br />
[http://www.sacred-texts.com/cla/luc/tsg/tsg07.htm Lucian, ''De Dea Syria''. Chapters. 50-51]:<br />
<br />
50. On certain days a multitude flocks into the temple, and the Galli in great numbers, sacred as they are, perform the ceremonies of the men and gash their arms and turn their backs to be lashed. Many bystanders play on the pipes the while many beat drums; others sing divine and sacred songs. All this performance takes place outside the temple, and those engaged in the ceremony enter not into the temple.<br />
<br />
51. During these days they are made Galli. As the Galli sing and celebrate their orgies, frenzy falls on many of them and many who had come as mere spectators afterwards are found to have committed the great act. I will narrate what they do. Any young man who has resolved on this action, strips off his clothes, and with a loud shout bursts into the midst of the crowd, and picks up a sword from a number of swords which I suppose have been kept ready for many years for this purpose. He takes it and castrates himself and then runs wild through the city, bearing in his hands what he has cut off. He casts it into any house at will, and from this house he receives women’s raiment and ornaments. Thus they act during their ceremonies of castration.<br />
<br />
52. The Galli, when dead, are not buried like other men, but when a Gallus dies his companions carry him out into the suburbs, and laying him out on the bier on which they had carried him they cover him with stones, and after this return home. They wait then for seven days, after which they enter the temple. Should they enter before this they would be guilty of blasphemy.<br />
<br />
(There is a question whether this rite relates to Cybele and Attis, depending on whether we identify the Syrian goddess with Cybele.)<br />
<br />
==Arnobius, 3-4th century AD==<br />
<br />
[http://www.tertullian.org/fathers2/ANF-06/anf06-138.htm#P7705_2431814 Arnobius the Elder, Against the Pagans, book 5, 5-7]:<br />
<br />
5. In Timotheus, who was no mean mythologist, and also in others equally well informed, the birth of the Great Mother of the gods, and the origin of her rites, are thus detailed, being derived-as he himself writes and suggests-from learned books of antiquities, and from his acquaintance with the most secret mysteries:-<br />
<br />
Within the confines of Phrygia, he says, there is a rock of unheard-of wildness in every respect, the name of which is Agdus, so named by the natives of that district. Stones taken from it, as Themis by her oracle had enjoined, Deucalion and Pyrrha threw upon the earth, at that time emptied of men; from which this Great Mother, too, as she is called, was fashioned along with the others, and animated by the deity. Her, given over to rest and sleep on the very summit of the rock, Jupiter assailed with lewdest desires. But when, after long strife, he could no accomplish what he had proposed to himself, he, baffled, spent his lust on the stone. This the rock received, and with many groanings Acdestis is born in the tenth month, being named from his mother rock.<br />
<br />
In him there had been resistless might, and a fierceness of disposition beyond control, a lust made furious, and derived from both sexes. He violently plundered and laid waste; he scattered destruction wherever the ferocity of his disposition had led him; he regarded not gods nor men, nor did he think anything more powerful than himself; he contemned earth, heaven, and the stars.<br />
<br />
6. Now, when it had been often considered in the councils of the gods, by what means it might be possible either to weaken or to curb his audacity, Liber, the rest hanging back, takes upon himself this task. With the strongest wine he drugs a spring much resorted to by Acdestis where he had been wont to assuage the heat and burning thirst roused in him by sport and hunting. Hither runs Acdestis to drink when he felt the need; he gulps down the draught too greedily into his gaping veins. Overcome by what he is quite unaccustomed to, he is in consequence sent fast asleep.<br />
<br />
Liber is near the snare which he had set; over his foot he throws one end of a halter formed of hairs, woven together very skilfully; with the other end he lays hold of his privy members. When the fumes of the wine passed off, Acdestis starts up furiously, and his foot dragging the noose, by his own strength he robs himself of his sex; with the tearing asunder of these parts there is an immense flow of blood; both are carried off and swallowed up by the earth; from them there suddenly springs up, covered with fruit, a pomegranate tree, seeing the beauty of which, with admiration, Nana, daughter of the king or river Sangarius, gathers and places in her bosom some of the fruit.<br />
<br />
By this she becomes pregnant; her father shuts her up, supposing that she had been debauched, and seeks to have her starved to death; she is kept alive by the mother of the gods with apples, and other food, and brings forth a child, but Sangarius orders it to be exposed.<br />
<br />
One Phorbas having found the child, takes it home, brings it up on goats’ milk; and as handsome fellows are so named in Lydia, or because the Phrygians in their own way of speaking call their goats attagi, it happened in consequence that the boy obtained the name Attis.<br />
<br />
Him the mother of the gods loved exceedingly, because he was of most surpassing beauty; and Acdestis, who was his companion, as he grew up fondling him, and bound to him by wicked compliance with his lust in the only way now possible, leading him through the wooded glades, and presenting him with the spoils of many wild beasts, which the boy Attis at first said boastfully were won by his own toil and labour. Afterwards, under the influence of wine, he admits that he is both loved by Acdestis, and honoured by him with the gifts brought from the forest; whence it is unlawful for those polluted by drinking wine to enter into his sanctuary, because it discovered his secret.<br />
<br />
7. Then Midas, king of Pessinus, wishing to withdraw the youth from so disgraceful an intimacy, resolves to give him his own daughter in marriage, and caused the gates of the town to be closed, that no one of evil omen might disturb their marriage joys.<br />
<br />
But the mother of the gods, knowing the fate of the youth, and that he would live among men in safety only so long as he was free from the ties of marriage, that no disaster might occur, enters the closed city, raising its walls with her head, which began to be crowned with towers in consequence. Acdestis, bursting with rage because of the boy’s being torn from himself, and brought to seek a wife, fills all the guests with frenzied madness: the Phrygians shriek aloud, panic-stricken at the appearance of the gods; a daughter of adulterous Gallus cuts off her breasts; Attis snatches the pipe borne by him who was goading them to frenzy; and he, too, now filled with furious passion, raving frantically and tossed about, throws himself down at last, and under a pine tree mutilates himself, saying, “Take these, Acdestis, for which you have stirred up so great and terribly perilous commotions.”<br />
<br />
With the streaming blood his life flies; but the Great Mother of the gods gathers the parts which had been cut off, and throws earth on them, having first covered them, and wrapped them in the garment of the dead. From the blood which had flowed springs a flower, the violet, and with this the tree is girt. Thence the custom began and arose, whereby you even now veil and wreath with flowers the sacred pine.<br />
<br />
The virgin who had been the bride, whose name, as Valerius the pontifex relates, was Ia, veils the breast of the lifeless youth with soft wool, sheds tears with Acdestis, and slays herself After her death her blood is changed into purple violets.<br />
<br />
The mother of the gods sheds tears also, from which springs an almond tree, signifying the bitterness of death. Then she bears away to her cave the pine tree, beneath which Attis had unmanned himself; and Acdestis joining in her wailings, she beats and wounds her breast, pacing round the trunk of the tree now at rest.<br />
<br />
Jupiter is begged by Acdestis that Attis may be restored to life: he does not permit it. What, however, fate allowed, he readily grants, that his body should not decay, that his hairs should always grow, that the least of his fingers should live, and should be kept ever in motion; content with which favours, it is said that Acdestis consecrated the body in Pessinus, and honoured it with yearly rites and priestly services.<br />
<br />
And:<br />
<br />
16. And yet how can you assert the falsehood of this story, when the very rites which you celebrate throughout the year testify that you believe these things to be true, and consider them perfectly trustworthy?<br />
<br />
For what is the meaning of that pine which on fixed days you always bring into the sanctuary of the mother of the gods? Is it not in imitation of that tree, beneath which the raging and ill-fated youth laid hands upon himself, and which the parent of the gods consecrated to relieve her sorrow?<br />
<br />
What mean the fleeces of wool with which you bind and surround the trunk of the tree? Is it not to recall the wools with which Ia covered the dying youth, and thought that she could procure some warmth for his limbs fast stiffening with cold? What mean the branches of the tree girt round and decked with wreaths of violets? Do they not mark this, how the Mother adorned with early flowers the pine which indicates and bears witness to the sad mishap?<br />
<br />
What mean the Galli with dishevelled hair beating their breasts with their palms? Do they not recall to memory those lamentations with which the tower-bearing Mother, along with the weeping Acdestis, wailing aloud, followed the boy? What means the abstinence from eating bread which you have named castus? Is it not in imitation of the time when the goddess abstained from Ceres’ fruit in her vehement sorrow?<br />
<br />
17. Or if the things which we say are not so declare, say yourselves-those effeminate and delicate men whom we see among you in the sacred rites of this deity-what business, what care, what concern have they there; and why do they like mourners wound their arms and breasts, and act as those dolefully circumstanced?<br />
<br />
What mean the wreaths, what the violets, what the swathings, the coverings of soft wools? Why, finally, is the very pine, but a little before swaying to and fro among the shrubs, an utterly inert log, set up in the temple of the Mother of the gods next, like some propitious and very venerable deity?<br />
<br />
For either this is the cause which we have found in your writings and treatises, and in that case it is clear that you do not celebrate divine rites, but give a representation of sad events; or if there is any other reason which the darkness of the mystery has withheld from us, even it also must be involved in the infamy of some shameful deed. For who would believe that there is any honour in that which the worthless Galli begin, effeminate debauchees complete?<br />
<br />
And ch. 39:<br />
<br />
39. Whence, then, do we prove that all these narratives are records of events? Froth the solemn rites and mysteries of initiation, it is clear, whether those which are celebrated at fixed times and on set days, or those which are taught secretly by the heathen without allowing the observance of their usages to be interrupted.<br />
<br />
For it is not to be believed that these have no origin, are practised without reason or meaning, and have no causes connected with their first beginnings. That pine which is regularly born into the sanctuary of the Great Mother, is it not in imitation of that tree beneath which Attis mutilated and unmanned himself, which also, they relate, the goddess consecrated to relieve her grief? That erecting of phalli and fascina, which Greece worships and celebrates in rites every year, does it not recall the deed by which Liber paid his debt?<br />
<br />
==Firmicus Maternus, ca. 350 AD==<br />
<br />
[http://www.roger-pearse.com/weblog/?p=1433 Firmicus Maternus, De errore profanum religionum, chap. 3]<br />
<br />
III. (1) The Phyrgians who live at Pessinus around the banks of the river Gallus, assign first place to the earth over the other elements, and this they profess (volunt) is the mother of all things. Then, so that they also might have for themselves an order of annual sacred events, they have consecrated the love affair of a rich women, their queen, who chose to punish tyrannically the scorn of an adolescent lover, with annual lamentations. And to satisfy the irate woman, or to find consolation for her remorse, he whom they had buried a little earlier, they claim that he had come back to life. And as the soul of the woman burned with the impatience of excessive love, they built temples to the dead youth. Then they profess that the priests appointed should undergo from themselves what the angry woman had done because of the injury to her scorned beauty. So in the annual sacred rites in honour of the earth the pomp of his funeral is organised, and when men are persuaded that they are honouring the earth, they are (in fact) venerating the death and funeral of a wretch.<br />
<br />
(2) Here also, most sacred emperors, in order to shield this error, they profess that these natural sacred rites are also arranged rationally. They profess that the earth loves its fruits, they profess that Attis is exactly this, which is born from fruits; however the punishment which he sustained, this they profess is what the reaper with his scythe does to the ripe fruits. They call it his death when the collected seeds are stored; life again, when the sown seeds sprout in the turning of the years.<br />
<br />
(3) I would like them now to reply to my inquiry, why have they associated this simple (story of) seed and fruit with a funeral, with death, with scorn, with punishment, with love? Was there not anything else that might be said? Was there not anything else that poor mortals might do in grateful thanks to the highest God for the crop? So that you can give thanks for the reborn crop, you howl; so that you rejoice, you weep. And you, when you see the true reason, you do not finally repent of doing this, but you do this, so that busyied with the turning seasons, you still flee from life, you pine for death.<br />
<br />
(4) Let them tell me, how it benefits the crop, that they renew their tears with yearly howlings, that they groan over the calamities of a reborn corpse, which they say is arranged for a natural reason. You mourn and you wail, and you cover your mourning with another excuse. The farmer knew when he could furrow the earth with a plow, when he could sow the furrows with grain, he knew when to gather the crop ripened by the heat of the sun, he knew when to tread out the dried crop. This is the natural reason, these are the true sacrificial rites, which are carried out by the yearly labour in men of healthy minds. The divinity asks for this simplicity, that men should follow the laws ordained of the seasons (temporum) in collecting crops. Why do they try to explain this order by wretched fictions of a death? Why is that shielded with tears, which does not need to be shielded? From which let them admit of necessity, that these rites are not held in honour of the crops, but in honour of an unworthy death.<br />
<br />
(5) When they say that the earth is the mother of all the gods, and they allot the chief roles to this element, indeed it is mother of their gods, — this we don’t deny or refuse, because from it they are always making their bunch of gods, whether of stone or wood. The sea flows around the whole earth, and again it is held tight by the circle of the encircling embracing Ocean. The heavens also are covered by the lofty dome, blown through by winds, splashed by rains, and in fear, as shown by tremors of unremitting motion. What remains to you, who cultivate these things, consider; when your gods reveal their weakness to you in daily declarations.<br />
<br />
And chapter 27, 1 (ACW p.104)<br />
<br />
Ch. 27] The accursed butcher schemed (oh the wickedness of it!) to have his cult always renewed by something wooden, because he foreknew that man's life, once nailed to the wood of the cross, would thereby be clasped in the embrace of everlasting immortality, and he wanted to fool doomed men by a counterfeit of the wood. In the Phrygian cult of her whom they call the Mother of the Gods, a pine tree is cut every year, and an image of a youth is fastened on the middle of the tree. In the cult of Isis the trunk of a pine tree is cut away. Its center is skilfully hollowed out, and an effigy of Osiris made of seeds is buried there. In the cult of Proserpina a tree is felled and shaped into the form and look of a virgin, and when it has been carried into the city there is mourning for forty nights and on the fortieth night it is burned. But a similar fire consumes also those other wooden things which I have mentioned, for after a year flames devour a pyre made precisely of these wooden objects. Unhappy man! You are wrong and emphatically wrong. That fire will not be able to do you any good. Vainly you flatter yourself about these flames; vainly you always renew the fire with your fablings. The fire which exacts the penalty for your misdeeds rages in a continuation of torment forever.<br />
<br />
==Julian the Apostate, 363 AD==<br />
<br />
[http://www.tertullian.org/fathers2/NPNF1-02/npnf1-02-12.htm#P1101_586858 Julian, Oratio 5: on the Magna Mater]:<br />
<br />
Who then is the Mother of the Gods? She is the Source of the Intelligible and Creative Powers, which direct the visible ones; she that gave birth to and copulated with the mighty Jupiter: she that exists as a great goddess next to the Great One, and in union with the Great Creator; she that is dispenser of all life; cause of all birth; most easily accomplishing all that is made; generating without passion; creating all that exists in concert with the Father; herself a virgin, without mother, sharing the throne of Jupiter, the mother in very truth of all the gods; for by receiving within herself the causes of all the intelligible deities that be above the world, she became the source to things the objects of intellect.<br />
<br />
Now this goddess, who is also the same as Providence, was seized with a love without passion for Attis. … And this the legend aims at teaching when it makes the Mother of the Gods enjoin upon Attis to be her servant, and not to stray from her, and not fall in love with another woman. But he went forward, and descended as far as the boundaries of Matter.<br />
<br />
But when it became necessary for this ignorance to cease and be stopped—-then Corybas, the mighty Sun, the colleague of the Mother of the Gods … persuades the lion to turn informer. Who then is this lion? We hear him styled “blazing”—-he must, therefore, I think, be the cause presiding over the hot and fiery element; that which was about to wage war against the Nymph, and to make her jealous of her intercourse with Attis; and who this Nymph is we have already stated.<br />
<br />
This lion, the fable tells, lent his aid to the Mother of the Gods … and by his detecting the offence and turning informer, became the author of the castration of the youth. … not without the intervention of the fabled madness of Attis…<br />
<br />
It is not therefore unreasonable to suppose this Attis a sixper-natural personage (in fact the fable implies as much), or rather in all respects, a deity, seeing that he comes forth out of the Third Creator, and returns again after his castration, to the Mother of the Gods… the fable styles him a “demi-god,” … The Corybantes… are assigned by the Great Mother to act as his bodyguard…<br />
<br />
This great god of ours is Attis; this is the meaning of the “Flight of King Attis” that we have just been lamenting; his “Concealments,” his “Vanishings,” his “Descents into the Cave.” Let my evidence be the time of year when all these ceremonies take place; for it is said that the Sacred Tree is cut down at the moment when the Sun arrives at the extreme point of the equinoctial arc: next in order follows the Sounding of the trumpets, and lastly is cut down the sacred and ineffable Harvest of the god Gallos: after these come, as they say, the Hilaria and festivities.<br />
<br />
Now that a “cessation of Indefinity” is meant by the castration so much talked of by the vulgar, is self-evident from the fact that when the Sun touches the equinoctial circle, where that which is most definite is placed (for equality is definite, but inequality indefinite and inexplicable); at that very moment (according to the report), the Sacred Tree is cut down; then come the other rites in their order; whereof some are done in compliance with rules that be holy and not to be divulged; others for reasons allowable to be discussed.<br />
<br />
The “Cutting of the Tree;” this part refers to the legend about the Gallos, and has nothing to do with the rites which it accompanies… The rite, therefore, enjoins upon us who are celestial by our nature, but who have been carried down to earth, to reap virtue joined with piety from our conduct upon earth, and to aspire upwards unto the deity, the primal source of being and the fount of life. Then immediately after the cutting does the trumpet give out the invocation to Attis and to those that be of heaven, whence we took our flight, and fell down to earth.<br />
<br />
And after this, when King Attis checks the Indefinity by the means of castration, the gods thereby warn us to extirpate in ourselves all incontinence, and to imitate the example, and to run upwards unto the Definite, and the Uniform, and if it be possible, to the One itself; which being accomplished the “Hilaria” must by all means follow. For what could be more contented, what more hilarious than the soul that has escaped from uncertainty, and generation, and the tumult that reigns therein, and hastens upwards to the gods? Of whose number was this Attis, whom the Mother of the Gods would not suffer to advance farther than was proper for him, but turned him towards herself, and enjoined him to check all indefinity.<br />
<br />
==Sallustius, mid-4th century AD==<br />
<br />
[http://www.sacred-texts.com/cla/fsgr/fsgr10.htm Sallustius, ''De diis et mundo''] - This is the Gilbert Murray 1925 translation, published as an appendix to "Five stages of Greek religion" and appearing on Sacred Texts. There is also an A.D.Nock 1926 translation, and there is an old one somewhere by Thomas Taylor. Sallustius was a friend of Julian the Apostate.<br />
<br />
To take another myth, they say that the Mother of the Gods seeing Attis lying by the river Gallus fell in love with him, took him, crowned him with her cap of stars, and thereafter kept him with her. He fell in love with a nymph and left the Mother to live with her. For this the Mother of the Gods made Attis go mad and cut off his genital organs and leave them with the nymph, and then return and dwell with her.<br />
<br />
Now the Mother of the Gods is the principle that generates life; that is why she is called Mother. Attis is the creator of all things which are born and die; that is why he is said to have been found by the river Gallus. For Gallus signifies the Galaxy, or Milky Way, the point at which body subject to passion begins. Now as the primary gods make perfect the secondary, the Mother loves Attis and gives him celestial powers.<br />
<br />
That is what the cap means. Attis loves a nymph: the nymphs preside over generation, since all that is generated is fluid. But since the process of generation must be stopped somewhere, and not allowed to generate something worse than the worst, the creator who makes these things casts away his generative powers into the creation and is joined to the Gods again. Now these things never happened, but always are. And mind sees all things at once, but reason (or speech) expresses some first and others after. Thus, as the myth is in accord with the cosmos, we for that reason keep a festival imitating the cosmos, for how could we attain higher order?<br />
<br />
==Anonymous, Carmen Ad Antonium, early 5th century (?)==<br />
<br />
[http://www.roger-pearse.com/weblog/?p=4402 here].<br />
<br />
Why do they hope for anything from Jupiter who came second after this king yet who is served with offerings through the lips of suppliants? This god has a mother, too, who was overtaken by love for a shepherd, so the shepherd himself came before Jupiter or Jove; but the shepherd was his superior for, wishing to preserve his chastity, he rejected the goddess who in her rage castrated him so that he who had refused to come to her bed should never be the husband of another. Was this the just ordinance of the gods however, that a man who had not been made a fornicator should never be a husband? Now, too, eunuchs chant shameful mysteries nor are there lacking men to be corrupted by this infection. They worship some secret the more profound for being behind closed doors and call holy something which would render a modest man unholy should he approach it. Thus the priest himself, more restricted, avoids sleeping with women and accepts the embrace of men.<br />
<br />
==Augustine, early 5th century AD==<br />
<br />
[http://www.tertullian.org/fathers2/NPNF1-02/npnf1-02-12.htm#P1101_586858 Augustine, City of God, book 6, chapter 7]:<br />
<br />
There are sacred rites of the mother of the gods, in which the beautiful youth Atys, loved by her, and castrated by her through a woman’s jealousy, is deplored by men who have suffered the like calamity, whom they call Galli. …<br />
<br />
What good is to be thought of their sacred rites which are concealed in darkness, when those which are brought forth into the light are so detestable? And certainly they themselves have seen what they transact in secret through the agency of mutilated and effeminate men. Yet they have not been able to conceal those same men miserably and vile enervated and corrupted.<br />
<br />
Let them persuade whom they can that they transact anything holy through such men, who, they cannot deny, are numbered, and live among their sacred things. We know not what they transact, but we know through whom they transact; for we know what things are transacted on the stage, where never, even in a chorus of harlots, hath one who is mutilated or an effeminate appeared.<br />
<br />
And, nevertheless, even these things are acted by vile and infamous characters; for, indeed, they ought not to be acted by men of good character. What, then, are those sacred rites, for the performance of which holiness has chosen such men as not even the obscenity of the stage has admitted?<br />
<br />
==Proclus, 5th century==<br />
<br />
[http://www.tertullian.org/fathers/marinus_01_life_of_proclus.htm Marinus, Life of Proclus, ch. 33]<br />
<br />
33. But if I was to enumerate all the facts of this kind, and to report the particular devotion which he held for Pan, son of Hermes, the great favors he received, and the numerous times he was, in Athens, saved by intervention of the divinity, and to relate in detail the protections and the advantages he received from the Mother of the Gods, of which he was particularly proud and happy, I would no doubt seem chattering vainly, to those who may light on this book by chance, and some may even think I am saying things little worthy of belief. For there were a considerable number of episodes, that were of almost daily occurrence, when this goddess [Cybele] spoke or acted in his favor; and their number and character are so unusual that I myself do not have their exact and precise memory.<br />
<br />
If anyone desires to know with what favor he was attached to this goddess, let him read Proclus's book on the Mother of the Gods, and it will be seen that with inspiration from on high he has been able to expound the whole theology relative to the goddess, and to explain philosophically all that the liturgical actions and the oral instructions mythically teach us about the goddess, and Attis, so that they will no longer be troubled by those seemingly absurd lamentations [for Attis] and all the secret traditions related in her ceremonies.<br />
<br />
==Damascius, early 6th century AD==<br />
<br />
From ''Life of Isidore'', as quoted by Photius, ''Bibliotheca'', codex 242.<br />
<br />
131. At Hierapolis in Phrygia there is a temple of Apollo and under the temple a subterranean fissue descends, which exhales lethal vapours. It is impossible to pass this gulf without danger, even for birds, and everyone who enters it dies. But the author says that it is possible for initiates to descend into the crevasse itself and stay there without injury. The author says that he himself and the philosopher Dorus, led by curiosity, descended into it and returned unharmed. The author says, “I then slept at Hierapolis and in a dream it seemed to me that I was Attis and that, by the order of the Great Mother of the gods, I was celebrating what is called the festival of the Hilaria; this dream signified our liberation from Hades. On returning to Aphrodisias, I recounted to Asclepiodotus the vision that I had in the dream. And he, full of admiration for what had happened to me, recounted to me, not “a dream for a dream”, but a great marvel in exchange for a little one.<br />
<br />
He said in fact that in his youth he had gone to that place to study the nature of it. He had rolled his mantle two and three times around his nostrils so that in the event of frequent fumes, he could breathe not the poisoned and deleterious air but pure and safe air which he had brought with him captured in his mantle. Proceeding thus, he entered on the descent, following a current of hot water which came out from there, and ran the length of the inaccessible crevasse. All the same he didn’t get to the bottom of the descent, because the access to it was cut off by the abundance of water and the passage was impossible to an ordinary man, but the one descending, possessed by the divinity, was carried to the bottom. Asclepiodotus then climbed back up from that place without injury thanks to his ingenuity. Later he even tried to recreate the lethal air using various ingredients.<br />
<br />
== John the Lydian ==<br />
<br />
''De Mensibus'' IV.41 reads:<br />
<br />
On day 11, the kalends of April, a pine tree is carried into the Palatine by the tree-bearers. But the emperor Claudius instituted these these ferias, a man of such justice in judgement that...<br />
<br />
=Inscriptions=<br />
<br />
The Clauss-Slaby database records a considerable number of inscriptions that mention Attis.<br />
<br />
==Attis Menotyrannus==<br />
<br />
In the following inscriptions, all from Rome and nowhere else, Attis is labelled "Menotyrannus". This may mean "Lord of the months", or derive from Men, the Phygian moon-god.<br />
<br />
Publication: CIL 06, 00499 p 3005, 3757 = CIL 06, 30779c = D 04147 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae Summae Parenti Hermae et Attidi Menotyranno Invicto Clodius Hermogenianus Caesarius vir clarissimus proconsul Africae praefectus urbis Romae XV vir sacris faciundis taurobolio criobolioque perfecto XIIII Kalendas Augustas diis animae suae mentisque custodibus aram dicavit domino nostro Gratiano Augusto tertium et 3 Aequitio conssulibus<br />
<br />
Publication: CIL 06, 00500 p 3005, 3757 = CIL 06, 30779d = D 04148 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno Conservatoribus suis Caelius Hilarianus vir clarissimus duodecimvir urbis Romae pater sacrorum et hieroceryx Invicti Mithrae sacerdos dei Liberi sacerdos deae Hecate domino nostro Gratiano Augusto et Merobaude conssulibus III Idus Maias<br />
<br />
Publication: CIL 06, 00501 p 3005, 3757 = CIL 06, 30779e = D 04149 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Sancto Menotyranno Quintus Clodius Flavianus vir clarissimus pontifex maior XV vir sacris faciundis septemvir epulonum pontifex dei Solis taurobolio criobolioque percepto aram dicavit Nonis Aprilibus FFllavis Merobaude II et Saturnino conssulibus<br />
<br />
Publication: CIL 06, 00508 p 3757 = D 04146 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Potentissimis Dis Matri deum Magnae et Attidi Menotyranno 3 Serapias honesta femina sacrata deum matris et Proserpinae taurobolium criobolium caernophorum perceptum per Flavium Antonium Eustochium sacerdotem Phryges maximus praesentibus et tradentibus cclarissimorum vvirorum ex amplissimo et sanctissimo collegio XV virum sacris faciundis die XIII Kalendas Maias cerealibus ddominis nnostris Constantino Maximo Augusto V et Licinio Iuniori Caesari conssulibus<br />
<br />
Publication: CIL 06, 00511 p 3005 = CLE 01529 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menoturano sacrum nobilis in causis forma celsusque Sabinus hic pater Invicti mystica victor habet sermo duos 3 reservans consimiles aufert3 et veneranda movet Cibeles Triodeia signa augentur meritis simbola tauroboli Rufius Caeionius Caeioni(?) Sabini filius(?) vir classimus pontifex maior hierofanta deae Hecatae augur publicus populi Romani Quiritium pater sacrorum Invicti Mthrae tauroboliatus Matris deum Magnae Idaeae et Attidis Minoturani et aram IIII Idus Martias Gratiano V et Merobaude consulibus dedicabit antiqua generose domo cui regia Vesta pontifici felix sacrato militat igne idem augur triplicis cultor venerande Dianae Persidicique Mithrae antistes Babloniae templi taurobolique simul magni dux mistice sacri<br />
<br />
Publication: AE 1953, 00238 = AE 2000, +00136 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Idaeae et Attidi sancto Menotyranno Alfenius Ceionius Iulianus Kamenius vir clarissimus VII vir epulonum pater et hieroceryx sacrorum Soli Invicti Mithrae hierofanta H{a}ecatae archibucolus dei liberi aram taurobolio criobolioque percepto dicabit! die XIIII Kalendas Augustas domino nostro Gratiano Augusto III et Equitio conssulibus<br />
<br />
Publication: CIL 06, 00512 p 3005, 3757 = CLE +00264 = D 04154 = SIRIS 00447 = RICIS-02, 005010212 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno dis Magnis et Tutatoribus suis Ceionius Rufius Volusianus vir clarissimus et inlustris ex vicario Asiae et Ceioni Rufi Volusiani viri clarissimi et inlustris ex praefecto praetorio et ex praefecto urbi et Caecinae Lollianae clarissimae et inlustris feminae deae Isidis sacerdotis filius iterato viginti annis expletis taurobolii sui aram constituit et consecravit X Kalendas Iunias domino nostro Valentiniano Augusto IIII et Neoterio conssulibus<br />
<br />
Publication: AE 1953, 00237 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Magnae Idaeae et Attidi Menotyranno Sextius Rusticus vir clarissimus et inlustris pater patrum dei Invicti Mithrae<br />
<br />
Publication: AE 1953, 00238 = AE 2000, +00136 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Idaeae et Attidi sancto Menotyranno Alfenius Ceionius Iulianus Kamenius vir clarissimus VII vir epulonum pater et hieroceryx sacrorum Soli Invicti Mithrae hierofanta Haecatae archibucolus dei liberi aram taurobolio criobolioque percepto dicabit! die XIIII Kalendas Augustas domino nostro Gratiano Augusto III et Equitio conssulibus<br />
<br />
Publication: CIL 06, 00499 p 3005, 3757 = CIL 06, 30779c = D 04147 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae Summae Parenti Hermae et Attidi Menotyranno Invicto Clodius Hermogenianus Caesarius vir clarissimus proconsul Africae praefectus urbis Romae XV vir sacris faciundis taurobolio criobolioque perfecto XIIII Kalendas Augustas diis animae suae mentisque custodibus aram dicavit domino nostro Gratiano Augusto tertium et 3 Aequitio conssulibus<br />
<br />
Publication: CIL 06, 00500 p 3005, 3757 = CIL 06, 30779d = D 04148 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno Conservatoribus suis Caelius Hilarianus vir clarissimus duodecimvir urbis Romae pater sacrorum et hieroceryx Invicti Mithrae sacerdos dei Liberi sacerdos deae Hecate domino nostro Gratiano Augusto et Merobaude conssulibus III Idus Maias<br />
<br />
Publication: CIL 06, 00501 p 3005, 3757 = CIL 06, 30779e = D 04149 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Sancto Menotyranno Quintus Clodius Flavianus vir clarissimus pontifex maior XVvir sacris faciundis septemvir epulonum pontifex dei Solis taurobolio criobolioque percepto aram dicavit Nonis Aprilibus FFllavis Merobaude II et Saturnino conssulibus<br />
<br />
Publication: CIL 06, 00508 p 3757 = D 04146 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Potentissimis Dis Matri deum Magnae et Attidi Menotyranno 3 Serapias honesta femina sacrata deum matris et Proserpinae taurobolium criobolium caernophorum perceptum per Flavium Antonium Eustochium sacerdotem Phryges maximus praesentibus et tradentibus cclarissimorum vvirorum ex amplissimo et sanctissimo collegio XV virum sacris faciundis die XIII Kalendas Maias cerealibus ddominis nnostris Constantino Maximo Augusto V et Licinio Iuniori Caesari conssulibus<br />
<br />
Publication: CIL 06, 00511 p 3005 = CLE 01529 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menoturano sacrum nobilis in causis forma celsusque Sabinus hic pater Invicti mystica victor habet sermo duos 3 reservans consimiles aufert et veneranda movet Cibeles Triodeia signa augentur meritis simbola tauroboli Rufius Caeionius Caeioni(?) Sabini filius(?) vir classimus pontifex maior hierofanta deae Hecatae augur publicus populi Romani Quiritium pater sacrorum Invicti Mthrae tauroboliatus Matris deum Magnae Idaeae et Attidis Minoturani et aram IIII Idus Martias Gratiano V et Merobaude consulibus dedicabit antiqua generose domo cui regia Vesta pontifici felix sacrato militat igne idem augur triplicis cultor venerande Dianae Persidicique Mithrae antistes Babloniae templi taurobolique simul magni dux mistice sacri<br />
<br />
Publication: CIL 06, 00512 p 3005, 3757 = CLE +00264 = D 04154 = SIRIS 00447 = RICIS-02, 005010212 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno dis Magnis et Tutatoribus suis Ceionius Rufius Volusianus vir clarissimus et inlustris ex vicario Asiae et Ceioni Rufi Volusiani viri clarissimi et inlustris ex praefecto praetorio et ex praefecto urbi et Caecinae Lollianae clarissimae et inlustris feminae deae Isidis sacerdotis filius iterato viginti annis expletis taurobolii sui aram constituit et consecravit X Kalendas Iunias domino nostro Valentiniano Augusto IIII et Neoterio conssulibus</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/Attis_Sources&diff=3056User:Roger Pearse/Attis Sources2022-02-10T16:10:10Z<p>Roger Pearse: /* Ovid, 1st century AD */</p>
<hr />
<div>These are the sources for our knowledge of Attis.<br />
<br />
=Literary Sources=<br />
<br />
==Herodotus, 5th century BC==<br />
<br />
In [http://www.sacred-texts.com/cla/hh/hh1030.htm Herodotus, book 1, 34-45], there is a rambling story about Atys, son of Croesus, accidentally killed by a spear while hunting. In his Cybele and Attis, M. J. Vermaseren considers whether this is part of the myth of Attis. [http://www.dur.ac.uk/Classics/histos/1998/lewis.html This link] asserts that it is.<br />
<br />
But on looking at the text, the account is very dissimilar from any other account. Does anything but the similarity of name tie the two together?<br />
<br />
==Catullus, 84 BC – ca. 54 BC==<br />
<br />
[http://www.vroma.org/~hwalker/VRomaCatullus/063.html Catullus, Poem 63]:<br />
<br />
<pre><br />
Borne in his swift bark over deep seas,<br />
Attis, when eagerly with speedy foot he reached the Phrygian woodland,<br />
and entered the goddess’ abodes, shadowy, forest-crowned;<br />
there, goaded by raging madness, bewildered in mind,<br />
he cast down from him with sharp flint-stone the burden of his member.<br />
So when she felt her limbs to have lost their manbood,<br />
still with fresh blood dabbling the face of the ground,<br />
swiftly with snowy bands she seized the light timbrel,<br />
your timbrel, Cybele, thy mysteries, Mother,<br />
and shaking with soft fingers the hollow oxhide<br />
thus began she to sing to her companions tremulously:<br />
“Come away, ye Gallae, go to the mountain forests of Cybele together,<br />
together go, wandering herd of the lady of Dindymus,<br />
who swiftly seeking alien homes as exiles,<br />
followed my rule as I led you in my train,<br />
endured the fast-flowing brine and the savage seas,<br />
and unmanned your bodies from utter abhorrence of love,<br />
cheer ye your Lady’s heart with swift wanderings.<br />
Let dull delay depart from your mind; go together, follow<br />
to the Phrygian house of Cybele, to the Phrygian forests of the goddess,<br />
where the noise of cymbals sounds, where timbrels re-echo,<br />
where the Phrygian flute-player blows a deep note on his curved reed,<br />
where the Maenads ivy-crowned toss their heads violently,<br />
where with shrill yells they shake the holy emblems,<br />
where that wandering company of the goddess is wont to rove,<br />
whither for us ’tis meet to hasten with rapid dances.”<br />
So soon as Attis, woman yet no true one, chanted thus to her companions,<br />
the revellers suddenly with quivering tongues yell aloud,<br />
the light timbrel rings again, clash again the hollow cymbals,<br />
swiftly to green Ida goes the rout with hurrying foot.<br />
Then too frenzied, panting, uncertain, wanders, gasping for breath,<br />
attended by the timbrel, Attis, through the dark forests their leader,<br />
as a heifer unbroken starting aside from the burden of the yoke.<br />
Fast follow the Gallae their swift-footed leader.<br />
So when they gained the house of Cybele, faint and weary,<br />
after much toil they take their rest without bread;<br />
heavy sleep covers their eyes with drooping weariness,<br />
the delirious madness of their mind departs in soft slumber.<br />
But when the sun with the flashing eyes of his golden face<br />
lightened the clear heaven, the firm lands, the wild sea,<br />
and chased away the shades of night with eager tramping steeds refreshed,<br />
then Sleep fled from wakened Attis and quickly was gone;<br />
him the goddess Pasithea received in her fluttering bosom.<br />
So after soft slumber, freed from violent madness,<br />
as soon as Attis himself in his heart reviewed his own deed,<br />
and saw with clear mind what lie had lost and where he was,<br />
with surging mind again he sped back to the waves.<br />
There, looking out upon the waste seas with streaming eyes,<br />
thus did she piteously address her country with tearful voice:<br />
” O my country that gavest me life! O my country that barest me!<br />
leaving whom, all wretch! as runaway servants leave their masters,<br />
I have borne my foot to the forests of Ida,<br />
to live among snows and frozen lairs of wild beasts,<br />
and visit in my frenzy all their lurking-dens,<br />
– where then or in what region do I think thy place to be, O my country?<br />
Mine eyeballs unbidden long to turn their gaze to thee<br />
while for a short space my mind is free from wild frenzy.<br />
I, shall I from my own home be borne far away into these forests?<br />
from my country, my possessions, my friends, my parents, shall I be?<br />
absent from the market, the wrestling-place, the racecourse, the playground?<br />
unhappy, all unhappy heart, again, again must thou complain.<br />
For what form of human figure is there which I had not?<br />
I, to be a woman–who was a stripling, I a youth, I a boy,<br />
I was the flower of the playground, I was once the glory of the palaestra:<br />
mine were the crowded doorways, mine the warm thresholds,<br />
mine the flowery garlands to deck my house<br />
when I was to leave my chamber at sunrise.<br />
I, shall I now be called–what? a handmaid of the gods, a ministress of Cybele?<br />
I a Maenad, I part of myself, a barren man shall I be?<br />
I, shall I dwell in icy snow-clad regions of verdant Ida,<br />
I pass my life under the high summits of Phrygia,<br />
with the hind that haunts the woodland, with the boar that ranges the forest?<br />
now, now I rue my deed, now, now I would it were undone.”<br />
From his rosy lips as these words issued forth,<br />
bringing a new message to both ears of the gods,<br />
then Cybele, loosening the fastened yoke from her lions,<br />
and goading that foe of the herd who drew on the left, thus speaks:<br />
“Come now,” she says, “come, go fiercely, let madness hunt him hence<br />
bid him hence by stroke of madness hie him to the forests again,<br />
him who would be too free, and run away from my sovereignty.<br />
Come, lash back with tail, endure thy own scourging,<br />
make all around resound with bellowing roar,<br />
shake fiercely on brawny neck thy ruddy mane.”<br />
Thus says wrathful Cybele, and with her hand unbinds the yoke.<br />
The monster stirs his courage and rouses him to fury of heart;<br />
he speeds away, he roars, with ranging foot he breaks the brushwood.<br />
But when he came to the watery stretches of the white-gleaming shore,<br />
and saw tender Attis by the smooth spaces of the sea,<br />
he rushes at him–madly flies Attis to the wild woodland.<br />
There always for all his lifetime was he a handmaid.<br />
Goddess, great goddess, Cybele, goddess, lady of Dindymus<br />
far from my house be all thy fury, O my queen<br />
others drive thou in frenzy, others drive thou to madness.<br />
</pre><br />
<br />
==Diodorus Siculus, 1st century BC==<br />
<br />
[http://penelope.uchicago.edu/Thayer/E/Roman/Texts/Diodorus_Siculus/3D*.html Diodorus Siculus, History, 3.58.4-59.1]:<br />
<br />
58. However, an account is handed down also that this goddess was born in Phrygia. For the natives of that country have the following myth: In ancient times Meïon became king of Phrygia and Lydia; and marrying Dindymê he begat an infant daughter, but being unwilling to rear her he exposed her on the mountain which was called Cybelus. There, in accordance with some divine providence, both the leopards and some of the other especially ferocious wild beasts offered their nipples to the child and so gave it nourishment, and some women who were tending the flocks in that place witnessed the happening, and being astonished at the strange event took up the babe and called her Cybelê after the name of the place. The child, as she grew up, excelled in both beauty and virtue and also came to be admired for her intelligence; for she was the first to devise the pipe of many reeds and to invent cymbals and kettledrums with which to accompany the games and the dance, and in addition she taught how to heal the sicknesses of both flocks and little children by means of rites of purification; in consequence, since the babes were saved from death by her spells and were generally taken up in her arms, her devotion to them and affection for them led all the people to speak of her as the “mother of the mountain.” The man who associated with her and loved her more than anyone else, they say, was Marsyas the physician, who was admired for his intelligence and chastity; and a proof of his intelligence they find in the fact that he imitated the sounds made by the pipe of many reeds and carried all its notes over into the flute, and as an indication of his chastity they cite his abstinence from sexual pleasures until the day of his death.<br />
<br />
Now Cybelê, the myth records, having arrived at full womanhood, came to love a certain native youth who was known as Attis, but at a later time received the appellation Papas; with him she consorted secretly and became with child, and at about the same time her parents recognized her as their child. Consequently she was brought up into the palace, and her father welcomed her at the outset under the impression the she was a virgin, but later, when he learned of her seduction, he put to death her nurses and Attis as well and cast their bodies forth to lie unburied; whereupon Cybelê, they say, because of her love for the youth and grief over the nurses, became frenzied and rushed out of the palace into the countryside. And crying aloud and beating upon a kettledrum she visited every country alone, with hair hanging free, and Marsyas, out of pity for her plight, voluntarily followed her and accompanied her in her wanderings because of the love which he had formerly borne her. … And Apollo, they say, laid away both the lyre and the pipes as a votive offering in the cave of Dionysus, and becoming enamoured of Cybelê joined in her wanderings as far as the land of the Hyperboreans.<br />
<br />
But, the myth goes on to say, a pestilence fell upon human beings throughout Phrygia and the land ceased to bear fruit, and when the unfortunate people inquired of the god how they might rid themselves of their ills he commanded them, it is said, to bury the body of Attis and to honour Cybelê as a goddess. Consequently the physicians, since the body had disappeared in the course of time, made an image of the youth, before which they sang dirges and by means of honours in keeping with his suffering propitiated the wrath of him who had been wronged; and these rites they continue to perform down to our own lifetime. As for Cybelê, in ancient times they erected altars and performed sacrifices to her yearly; and later they built for her a costly temple in Pisinus of Phrygia, and established honours and sacrifices of the greatest magnificence, Midas their king taking part in all these works out of his devotion to beauty; and beside the statue of the goddess they set up panthers and lions, since it was the common opinion that she had first been nursed by these animals.<br />
<br />
Such, then, are the myths which are told about Mother of the God both among the Phrygians and by the Atlantians who dwell on the coast of the ocean.<br />
<br />
==Ovid, 1st century AD==<br />
<br />
[http://www.tkline.freeserve.co.uk/OvidFastiBkFour.htm Ovid, Fasti, 4.221-224]:<br />
<br />
<pre><br />
… I said ‘Where did this urge to cut off<br />
Their members come from?’ As I ended, the Muse spoke:<br />
‘In the woods, a Phrygian boy, Attis, of handsome face,<br />
Won the tower-bearing goddess with his chaste passion.<br />
She desired him to serve her, and protect her temple,<br />
And said: “Wish, you might be a boy for ever.”<br />
He promised to be true, and said: “If I’m lying<br />
May the love I fail in be my last love.”<br />
He did fail, and in meeting the nymph Sagaritis,<br />
Abandoned what he was: the goddess, angered, avenged it.<br />
She destroyed the Naiad, by wounding a tree,<br />
Since the tree contained the Naiad’s fate.<br />
Attis was maddened, and thinking his chamber’s roof<br />
Was falling, fled for the summit of Mount Dindymus.<br />
Now he cried: “Remove the torches”, now he cried:<br />
“Take the whips away”: often swearing he saw the Furies.<br />
He tore at his body too with a sharp stone,<br />
And dragged his long hair in the filthy dust,<br />
Shouting: “I deserved this! I pay the due penalty<br />
In blood! Ah! Let the parts that harmed me, perish!<br />
Let them perish!” cutting away the burden of his groin,<br />
And suddenly bereft of every mark of manhood.<br />
His madness set a precedent, and his unmanly servants<br />
Toss their hair, and cut off their members as if worthless.’<br />
So the Aonian Muse, eloquently answering the question<br />
I’d asked her, regarding the causes of their madness.<br />
</pre><br />
<br />
[https://ovid.lib.virginia.edu/trans/Metamorph10.htm#484521419 Ovid, Metamorphoses (X.103-5)]:<br />
<br />
You came, also, ... the pliant palms, the winner’s prize; and you, the shaggy-topped pine tree, armed with needles, sacred to Cybele, mother of the gods, since Attis exchanged his human form for you, and hardened in your trunk.<br />
<br />
==Pausanias, 2nd century AD==<br />
<br />
[http://books.google.co.uk/books?dq=pausanias+description+of+greece&pg=PA191&id=p6oAAAAAYAAJ&ots=mmAB61GsT0 Pausanius, Guide to Greece, 7.17.5]:<br />
<br />
The Achaian city Dyme is distant about four hundred stadia from Larissus… Besides this the Dymaei have a temple of Minerva, and a statue of the goddess, which is very ancient. They have also another temple sacred to the mother Dindymene, and Attes. But who Attes is, I have not been able to discover, because it is. an arcane affair. Hermesianax, indeed, a writer of elegies, says, that he was the son of the Phrygian Calaus, and that he was produced by his mother incapable of begetting children. That when he arrived at manhood he migrated to Lydia, and established there the orgies of the Great Mother. And that he was so highly honoured by the goddess, that it excited the indignation of Jupiter, who sent a boar into the Lydian fields, by which other Lydians were destroyed, and Attes himself was slain. The Gauls who inhabit Pesinus, confirm by their conduct the truth of this relation, for they cannot bear to touch swine. However, they report things concerning Attes far different from the above.<br />
<br />
Jupiter, say they, while he was asleep emitted his seed on the earth; this in process of time produced a daemon with twofold private parts, viz. with the parts of man and woman united. The name of this daemon was Agdistis: and the gods, in consequence of being terrified at him, cut off his virile parts. From these parts an almond tree was produced, the fruit of which, when ripe, the daughter of the river Sangarius gathered and concealed in her bosom. The fruit, however, immediately vanished, and she became pregnant. As the result of her pregnancy, she was delivered of a boy, who being left in the woods was educated by a goat, and who, as he grew in years, possessed a beauty surpassing that of the human form, and through which Agdistis fell in love with him. But when he arrived at manhood, his friends sent him to Pesinus, in order that he might marry the daughter of the king. Here, as they were singing the nuptial song, Agdistis presented himself before them, and Attes becoming insane, cut off his private parts. The king’s daughter, too, that was given to Attes, cut off her privities. But Agdistis was grieved that Attes had acted in this manner, and obtained of Jupiter that no part of the body of Attes should either become putrid or waste away. And such are the particulars which are reported about Attes.<br />
<br />
==Lucian, 2nd century AD==<br />
<br />
[http://www.sacred-texts.com/cla/luc/tsg/tsg07.htm Lucian, ''De Dea Syria''. Chapters. 50-51]:<br />
<br />
50. On certain days a multitude flocks into the temple, and the Galli in great numbers, sacred as they are, perform the ceremonies of the men and gash their arms and turn their backs to be lashed. Many bystanders play on the pipes the while many beat drums; others sing divine and sacred songs. All this performance takes place outside the temple, and those engaged in the ceremony enter not into the temple.<br />
<br />
51. During these days they are made Galli. As the Galli sing and celebrate their orgies, frenzy falls on many of them and many who had come as mere spectators afterwards are found to have committed the great act. I will narrate what they do. Any young man who has resolved on this action, strips off his clothes, and with a loud shout bursts into the midst of the crowd, and picks up a sword from a number of swords which I suppose have been kept ready for many years for this purpose. He takes it and castrates himself and then runs wild through the city, bearing in his hands what he has cut off. He casts it into any house at will, and from this house he receives women’s raiment and ornaments. Thus they act during their ceremonies of castration.<br />
<br />
52. The Galli, when dead, are not buried like other men, but when a Gallus dies his companions carry him out into the suburbs, and laying him out on the bier on which they had carried him they cover him with stones, and after this return home. They wait then for seven days, after which they enter the temple. Should they enter before this they would be guilty of blasphemy.<br />
<br />
(There is a question whether this rite relates to Cybele and Attis, depending on whether we identify the Syrian goddess with Cybele.)<br />
<br />
==Arnobius, 3-4th century AD==<br />
<br />
[http://www.tertullian.org/fathers2/ANF-06/anf06-138.htm#P7705_2431814 Arnobius the Elder, Against the Pagans, book 5, 5-7]:<br />
<br />
5. In Timotheus, who was no mean mythologist, and also in others equally well informed, the birth of the Great Mother of the gods, and the origin of her rites, are thus detailed, being derived-as he himself writes and suggests-from learned books of antiquities, and from his acquaintance with the most secret mysteries:-<br />
<br />
Within the confines of Phrygia, he says, there is a rock of unheard-of wildness in every respect, the name of which is Agdus, so named by the natives of that district. Stones taken from it, as Themis by her oracle had enjoined, Deucalion and Pyrrha threw upon the earth, at that time emptied of men; from which this Great Mother, too, as she is called, was fashioned along with the others, and animated by the deity. Her, given over to rest and sleep on the very summit of the rock, Jupiter assailed with lewdest desires. But when, after long strife, he could no accomplish what he had proposed to himself, he, baffled, spent his lust on the stone. This the rock received, and with many groanings Acdestis is born in the tenth month, being named from his mother rock.<br />
<br />
In him there had been resistless might, and a fierceness of disposition beyond control, a lust made furious, and derived from both sexes. He violently plundered and laid waste; he scattered destruction wherever the ferocity of his disposition had led him; he regarded not gods nor men, nor did he think anything more powerful than himself; he contemned earth, heaven, and the stars.<br />
<br />
6. Now, when it had been often considered in the councils of the gods, by what means it might be possible either to weaken or to curb his audacity, Liber, the rest hanging back, takes upon himself this task. With the strongest wine he drugs a spring much resorted to by Acdestis where he had been wont to assuage the heat and burning thirst roused in him by sport and hunting. Hither runs Acdestis to drink when he felt the need; he gulps down the draught too greedily into his gaping veins. Overcome by what he is quite unaccustomed to, he is in consequence sent fast asleep.<br />
<br />
Liber is near the snare which he had set; over his foot he throws one end of a halter formed of hairs, woven together very skilfully; with the other end he lays hold of his privy members. When the fumes of the wine passed off, Acdestis starts up furiously, and his foot dragging the noose, by his own strength he robs himself of his sex; with the tearing asunder of these parts there is an immense flow of blood; both are carried off and swallowed up by the earth; from them there suddenly springs up, covered with fruit, a pomegranate tree, seeing the beauty of which, with admiration, Nana, daughter of the king or river Sangarius, gathers and places in her bosom some of the fruit.<br />
<br />
By this she becomes pregnant; her father shuts her up, supposing that she had been debauched, and seeks to have her starved to death; she is kept alive by the mother of the gods with apples, and other food, and brings forth a child, but Sangarius orders it to be exposed.<br />
<br />
One Phorbas having found the child, takes it home, brings it up on goats’ milk; and as handsome fellows are so named in Lydia, or because the Phrygians in their own way of speaking call their goats attagi, it happened in consequence that the boy obtained the name Attis.<br />
<br />
Him the mother of the gods loved exceedingly, because he was of most surpassing beauty; and Acdestis, who was his companion, as he grew up fondling him, and bound to him by wicked compliance with his lust in the only way now possible, leading him through the wooded glades, and presenting him with the spoils of many wild beasts, which the boy Attis at first said boastfully were won by his own toil and labour. Afterwards, under the influence of wine, he admits that he is both loved by Acdestis, and honoured by him with the gifts brought from the forest; whence it is unlawful for those polluted by drinking wine to enter into his sanctuary, because it discovered his secret.<br />
<br />
7. Then Midas, king of Pessinus, wishing to withdraw the youth from so disgraceful an intimacy, resolves to give him his own daughter in marriage, and caused the gates of the town to be closed, that no one of evil omen might disturb their marriage joys.<br />
<br />
But the mother of the gods, knowing the fate of the youth, and that he would live among men in safety only so long as he was free from the ties of marriage, that no disaster might occur, enters the closed city, raising its walls with her head, which began to be crowned with towers in consequence. Acdestis, bursting with rage because of the boy’s being torn from himself, and brought to seek a wife, fills all the guests with frenzied madness: the Phrygians shriek aloud, panic-stricken at the appearance of the gods; a daughter of adulterous Gallus cuts off her breasts; Attis snatches the pipe borne by him who was goading them to frenzy; and he, too, now filled with furious passion, raving frantically and tossed about, throws himself down at last, and under a pine tree mutilates himself, saying, “Take these, Acdestis, for which you have stirred up so great and terribly perilous commotions.”<br />
<br />
With the streaming blood his life flies; but the Great Mother of the gods gathers the parts which had been cut off, and throws earth on them, having first covered them, and wrapped them in the garment of the dead. From the blood which had flowed springs a flower, the violet, and with this the tree is girt. Thence the custom began and arose, whereby you even now veil and wreath with flowers the sacred pine.<br />
<br />
The virgin who had been the bride, whose name, as Valerius the pontifex relates, was Ia, veils the breast of the lifeless youth with soft wool, sheds tears with Acdestis, and slays herself After her death her blood is changed into purple violets.<br />
<br />
The mother of the gods sheds tears also, from which springs an almond tree, signifying the bitterness of death. Then she bears away to her cave the pine tree, beneath which Attis had unmanned himself; and Acdestis joining in her wailings, she beats and wounds her breast, pacing round the trunk of the tree now at rest.<br />
<br />
Jupiter is begged by Acdestis that Attis may be restored to life: he does not permit it. What, however, fate allowed, he readily grants, that his body should not decay, that his hairs should always grow, that the least of his fingers should live, and should be kept ever in motion; content with which favours, it is said that Acdestis consecrated the body in Pessinus, and honoured it with yearly rites and priestly services.<br />
<br />
And:<br />
<br />
16. And yet how can you assert the falsehood of this story, when the very rites which you celebrate throughout the year testify that you believe these things to be true, and consider them perfectly trustworthy?<br />
<br />
For what is the meaning of that pine which on fixed days you always bring into the sanctuary of the mother of the gods? Is it not in imitation of that tree, beneath which the raging and ill-fated youth laid hands upon himself, and which the parent of the gods consecrated to relieve her sorrow?<br />
<br />
What mean the fleeces of wool with which you bind and surround the trunk of the tree? Is it not to recall the wools with which Ia covered the dying youth, and thought that she could procure some warmth for his limbs fast stiffening with cold? What mean the branches of the tree girt round and decked with wreaths of violets? Do they not mark this, how the Mother adorned with early flowers the pine which indicates and bears witness to the sad mishap?<br />
<br />
What mean the Galli with dishevelled hair beating their breasts with their palms? Do they not recall to memory those lamentations with which the tower-bearing Mother, along with the weeping Acdestis, wailing aloud, followed the boy? What means the abstinence from eating bread which you have named castus? Is it not in imitation of the time when the goddess abstained from Ceres’ fruit in her vehement sorrow?<br />
<br />
17. Or if the things which we say are not so declare, say yourselves-those effeminate and delicate men whom we see among you in the sacred rites of this deity-what business, what care, what concern have they there; and why do they like mourners wound their arms and breasts, and act as those dolefully circumstanced?<br />
<br />
What mean the wreaths, what the violets, what the swathings, the coverings of soft wools? Why, finally, is the very pine, but a little before swaying to and fro among the shrubs, an utterly inert log, set up in the temple of the Mother of the gods next, like some propitious and very venerable deity?<br />
<br />
For either this is the cause which we have found in your writings and treatises, and in that case it is clear that you do not celebrate divine rites, but give a representation of sad events; or if there is any other reason which the darkness of the mystery has withheld from us, even it also must be involved in the infamy of some shameful deed. For who would believe that there is any honour in that which the worthless Galli begin, effeminate debauchees complete?<br />
<br />
And ch. 39:<br />
<br />
39. Whence, then, do we prove that all these narratives are records of events? Froth the solemn rites and mysteries of initiation, it is clear, whether those which are celebrated at fixed times and on set days, or those which are taught secretly by the heathen without allowing the observance of their usages to be interrupted.<br />
<br />
For it is not to be believed that these have no origin, are practised without reason or meaning, and have no causes connected with their first beginnings. That pine which is regularly born into the sanctuary of the Great Mother, is it not in imitation of that tree beneath which Attis mutilated and unmanned himself, which also, they relate, the goddess consecrated to relieve her grief? That erecting of phalli and fascina, which Greece worships and celebrates in rites every year, does it not recall the deed by which Liber paid his debt?<br />
<br />
==Firmicus Maternus, ca. 350 AD==<br />
<br />
[http://www.roger-pearse.com/weblog/?p=1433 Firmicus Maternus, De errore profanum religionum, chap. 3]<br />
<br />
III. (1) The Phyrgians who live at Pessinus around the banks of the river Gallus, assign first place to the earth over the other elements, and this they profess (volunt) is the mother of all things. Then, so that they also might have for themselves an order of annual sacred events, they have consecrated the love affair of a rich women, their queen, who chose to punish tyrannically the scorn of an adolescent lover, with annual lamentations. And to satisfy the irate woman, or to find consolation for her remorse, he whom they had buried a little earlier, they claim that he had come back to life. And as the soul of the woman burned with the impatience of excessive love, they built temples to the dead youth. Then they profess that the priests appointed should undergo from themselves what the angry woman had done because of the injury to her scorned beauty. So in the annual sacred rites in honour of the earth the pomp of his funeral is organised, and when men are persuaded that they are honouring the earth, they are (in fact) venerating the death and funeral of a wretch.<br />
<br />
(2) Here also, most sacred emperors, in order to shield this error, they profess that these natural sacred rites are also arranged rationally. They profess that the earth loves its fruits, they profess that Attis is exactly this, which is born from fruits; however the punishment which he sustained, this they profess is what the reaper with his scythe does to the ripe fruits. They call it his death when the collected seeds are stored; life again, when the sown seeds sprout in the turning of the years.<br />
<br />
(3) I would like them now to reply to my inquiry, why have they associated this simple (story of) seed and fruit with a funeral, with death, with scorn, with punishment, with love? Was there not anything else that might be said? Was there not anything else that poor mortals might do in grateful thanks to the highest God for the crop? So that you can give thanks for the reborn crop, you howl; so that you rejoice, you weep. And you, when you see the true reason, you do not finally repent of doing this, but you do this, so that busyied with the turning seasons, you still flee from life, you pine for death.<br />
<br />
(4) Let them tell me, how it benefits the crop, that they renew their tears with yearly howlings, that they groan over the calamities of a reborn corpse, which they say is arranged for a natural reason. You mourn and you wail, and you cover your mourning with another excuse. The farmer knew when he could furrow the earth with a plow, when he could sow the furrows with grain, he knew when to gather the crop ripened by the heat of the sun, he knew when to tread out the dried crop. This is the natural reason, these are the true sacrificial rites, which are carried out by the yearly labour in men of healthy minds. The divinity asks for this simplicity, that men should follow the laws ordained of the seasons (temporum) in collecting crops. Why do they try to explain this order by wretched fictions of a death? Why is that shielded with tears, which does not need to be shielded? From which let them admit of necessity, that these rites are not held in honour of the crops, but in honour of an unworthy death.<br />
<br />
(5) When they say that the earth is the mother of all the gods, and they allot the chief roles to this element, indeed it is mother of their gods, — this we don’t deny or refuse, because from it they are always making their bunch of gods, whether of stone or wood. The sea flows around the whole earth, and again it is held tight by the circle of the encircling embracing Ocean. The heavens also are covered by the lofty dome, blown through by winds, splashed by rains, and in fear, as shown by tremors of unremitting motion. What remains to you, who cultivate these things, consider; when your gods reveal their weakness to you in daily declarations.<br />
<br />
==Julian the Apostate, 363 AD==<br />
<br />
[http://www.tertullian.org/fathers2/NPNF1-02/npnf1-02-12.htm#P1101_586858 Julian, Oratio 5: on the Magna Mater]:<br />
<br />
Who then is the Mother of the Gods? She is the Source of the Intelligible and Creative Powers, which direct the visible ones; she that gave birth to and copulated with the mighty Jupiter: she that exists as a great goddess next to the Great One, and in union with the Great Creator; she that is dispenser of all life; cause of all birth; most easily accomplishing all that is made; generating without passion; creating all that exists in concert with the Father; herself a virgin, without mother, sharing the throne of Jupiter, the mother in very truth of all the gods; for by receiving within herself the causes of all the intelligible deities that be above the world, she became the source to things the objects of intellect.<br />
<br />
Now this goddess, who is also the same as Providence, was seized with a love without passion for Attis. … And this the legend aims at teaching when it makes the Mother of the Gods enjoin upon Attis to be her servant, and not to stray from her, and not fall in love with another woman. But he went forward, and descended as far as the boundaries of Matter.<br />
<br />
But when it became necessary for this ignorance to cease and be stopped—-then Corybas, the mighty Sun, the colleague of the Mother of the Gods … persuades the lion to turn informer. Who then is this lion? We hear him styled “blazing”—-he must, therefore, I think, be the cause presiding over the hot and fiery element; that which was about to wage war against the Nymph, and to make her jealous of her intercourse with Attis; and who this Nymph is we have already stated.<br />
<br />
This lion, the fable tells, lent his aid to the Mother of the Gods … and by his detecting the offence and turning informer, became the author of the castration of the youth. … not without the intervention of the fabled madness of Attis…<br />
<br />
It is not therefore unreasonable to suppose this Attis a sixper-natural personage (in fact the fable implies as much), or rather in all respects, a deity, seeing that he comes forth out of the Third Creator, and returns again after his castration, to the Mother of the Gods… the fable styles him a “demi-god,” … The Corybantes… are assigned by the Great Mother to act as his bodyguard…<br />
<br />
This great god of ours is Attis; this is the meaning of the “Flight of King Attis” that we have just been lamenting; his “Concealments,” his “Vanishings,” his “Descents into the Cave.” Let my evidence be the time of year when all these ceremonies take place; for it is said that the Sacred Tree is cut down at the moment when the Sun arrives at the extreme point of the equinoctial arc: next in order follows the Sounding of the trumpets, and lastly is cut down the sacred and ineffable Harvest of the god Gallos: after these come, as they say, the Hilaria and festivities.<br />
<br />
Now that a “cessation of Indefinity” is meant by the castration so much talked of by the vulgar, is self-evident from the fact that when the Sun touches the equinoctial circle, where that which is most definite is placed (for equality is definite, but inequality indefinite and inexplicable); at that very moment (according to the report), the Sacred Tree is cut down; then come the other rites in their order; whereof some are done in compliance with rules that be holy and not to be divulged; others for reasons allowable to be discussed.<br />
<br />
The “Cutting of the Tree;” this part refers to the legend about the Gallos, and has nothing to do with the rites which it accompanies… The rite, therefore, enjoins upon us who are celestial by our nature, but who have been carried down to earth, to reap virtue joined with piety from our conduct upon earth, and to aspire upwards unto the deity, the primal source of being and the fount of life. Then immediately after the cutting does the trumpet give out the invocation to Attis and to those that be of heaven, whence we took our flight, and fell down to earth.<br />
<br />
And after this, when King Attis checks the Indefinity by the means of castration, the gods thereby warn us to extirpate in ourselves all incontinence, and to imitate the example, and to run upwards unto the Definite, and the Uniform, and if it be possible, to the One itself; which being accomplished the “Hilaria” must by all means follow. For what could be more contented, what more hilarious than the soul that has escaped from uncertainty, and generation, and the tumult that reigns therein, and hastens upwards to the gods? Of whose number was this Attis, whom the Mother of the Gods would not suffer to advance farther than was proper for him, but turned him towards herself, and enjoined him to check all indefinity.<br />
<br />
==Sallustius, mid-4th century AD==<br />
<br />
[http://www.sacred-texts.com/cla/fsgr/fsgr10.htm Sallustius, ''De diis et mundo''] - This is the Gilbert Murray 1925 translation, published as an appendix to "Five stages of Greek religion" and appearing on Sacred Texts. There is also an A.D.Nock 1926 translation, and there is an old one somewhere by Thomas Taylor. Sallustius was a friend of Julian the Apostate.<br />
<br />
To take another myth, they say that the Mother of the Gods seeing Attis lying by the river Gallus fell in love with him, took him, crowned him with her cap of stars, and thereafter kept him with her. He fell in love with a nymph and left the Mother to live with her. For this the Mother of the Gods made Attis go mad and cut off his genital organs and leave them with the nymph, and then return and dwell with her.<br />
<br />
Now the Mother of the Gods is the principle that generates life; that is why she is called Mother. Attis is the creator of all things which are born and die; that is why he is said to have been found by the river Gallus. For Gallus signifies the Galaxy, or Milky Way, the point at which body subject to passion begins. Now as the primary gods make perfect the secondary, the Mother loves Attis and gives him celestial powers.<br />
<br />
That is what the cap means. Attis loves a nymph: the nymphs preside over generation, since all that is generated is fluid. But since the process of generation must be stopped somewhere, and not allowed to generate something worse than the worst, the creator who makes these things casts away his generative powers into the creation and is joined to the Gods again. Now these things never happened, but always are. And mind sees all things at once, but reason (or speech) expresses some first and others after. Thus, as the myth is in accord with the cosmos, we for that reason keep a festival imitating the cosmos, for how could we attain higher order?<br />
<br />
==Anonymous, Carmen Ad Antonium, early 5th century (?)==<br />
<br />
[http://www.roger-pearse.com/weblog/?p=4402 here].<br />
<br />
Why do they hope for anything from Jupiter who came second after this king yet who is served with offerings through the lips of suppliants? This god has a mother, too, who was overtaken by love for a shepherd, so the shepherd himself came before Jupiter or Jove; but the shepherd was his superior for, wishing to preserve his chastity, he rejected the goddess who in her rage castrated him so that he who had refused to come to her bed should never be the husband of another. Was this the just ordinance of the gods however, that a man who had not been made a fornicator should never be a husband? Now, too, eunuchs chant shameful mysteries nor are there lacking men to be corrupted by this infection. They worship some secret the more profound for being behind closed doors and call holy something which would render a modest man unholy should he approach it. Thus the priest himself, more restricted, avoids sleeping with women and accepts the embrace of men.<br />
<br />
==Augustine, early 5th century AD==<br />
<br />
[http://www.tertullian.org/fathers2/NPNF1-02/npnf1-02-12.htm#P1101_586858 Augustine, City of God, book 6, chapter 7]:<br />
<br />
There are sacred rites of the mother of the gods, in which the beautiful youth Atys, loved by her, and castrated by her through a woman’s jealousy, is deplored by men who have suffered the like calamity, whom they call Galli. …<br />
<br />
What good is to be thought of their sacred rites which are concealed in darkness, when those which are brought forth into the light are so detestable? And certainly they themselves have seen what they transact in secret through the agency of mutilated and effeminate men. Yet they have not been able to conceal those same men miserably and vile enervated and corrupted.<br />
<br />
Let them persuade whom they can that they transact anything holy through such men, who, they cannot deny, are numbered, and live among their sacred things. We know not what they transact, but we know through whom they transact; for we know what things are transacted on the stage, where never, even in a chorus of harlots, hath one who is mutilated or an effeminate appeared.<br />
<br />
And, nevertheless, even these things are acted by vile and infamous characters; for, indeed, they ought not to be acted by men of good character. What, then, are those sacred rites, for the performance of which holiness has chosen such men as not even the obscenity of the stage has admitted?<br />
<br />
==Proclus, 5th century==<br />
<br />
[http://www.tertullian.org/fathers/marinus_01_life_of_proclus.htm Marinus, Life of Proclus, ch. 33]<br />
<br />
33. But if I was to enumerate all the facts of this kind, and to report the particular devotion which he held for Pan, son of Hermes, the great favors he received, and the numerous times he was, in Athens, saved by intervention of the divinity, and to relate in detail the protections and the advantages he received from the Mother of the Gods, of which he was particularly proud and happy, I would no doubt seem chattering vainly, to those who may light on this book by chance, and some may even think I am saying things little worthy of belief. For there were a considerable number of episodes, that were of almost daily occurrence, when this goddess [Cybele] spoke or acted in his favor; and their number and character are so unusual that I myself do not have their exact and precise memory.<br />
<br />
If anyone desires to know with what favor he was attached to this goddess, let him read Proclus's book on the Mother of the Gods, and it will be seen that with inspiration from on high he has been able to expound the whole theology relative to the goddess, and to explain philosophically all that the liturgical actions and the oral instructions mythically teach us about the goddess, and Attis, so that they will no longer be troubled by those seemingly absurd lamentations [for Attis] and all the secret traditions related in her ceremonies.<br />
<br />
==Damascius, early 6th century AD==<br />
<br />
From ''Life of Isidore'', as quoted by Photius, ''Bibliotheca'', codex 242.<br />
<br />
131. At Hierapolis in Phrygia there is a temple of Apollo and under the temple a subterranean fissue descends, which exhales lethal vapours. It is impossible to pass this gulf without danger, even for birds, and everyone who enters it dies. But the author says that it is possible for initiates to descend into the crevasse itself and stay there without injury. The author says that he himself and the philosopher Dorus, led by curiosity, descended into it and returned unharmed. The author says, “I then slept at Hierapolis and in a dream it seemed to me that I was Attis and that, by the order of the Great Mother of the gods, I was celebrating what is called the festival of the Hilaria; this dream signified our liberation from Hades. On returning to Aphrodisias, I recounted to Asclepiodotus the vision that I had in the dream. And he, full of admiration for what had happened to me, recounted to me, not “a dream for a dream”, but a great marvel in exchange for a little one.<br />
<br />
He said in fact that in his youth he had gone to that place to study the nature of it. He had rolled his mantle two and three times around his nostrils so that in the event of frequent fumes, he could breathe not the poisoned and deleterious air but pure and safe air which he had brought with him captured in his mantle. Proceeding thus, he entered on the descent, following a current of hot water which came out from there, and ran the length of the inaccessible crevasse. All the same he didn’t get to the bottom of the descent, because the access to it was cut off by the abundance of water and the passage was impossible to an ordinary man, but the one descending, possessed by the divinity, was carried to the bottom. Asclepiodotus then climbed back up from that place without injury thanks to his ingenuity. Later he even tried to recreate the lethal air using various ingredients.<br />
<br />
== John the Lydian ==<br />
<br />
''De Mensibus'' IV.41 reads:<br />
<br />
On day 11, the kalends of April, a pine tree is carried into the Palatine by the tree-bearers. But the emperor Claudius instituted these these ferias, a man of such justice in judgement that...<br />
<br />
=Inscriptions=<br />
<br />
The Clauss-Slaby database records a considerable number of inscriptions that mention Attis.<br />
<br />
==Attis Menotyrannus==<br />
<br />
In the following inscriptions, all from Rome and nowhere else, Attis is labelled "Menotyrannus". This may mean "Lord of the months", or derive from Men, the Phygian moon-god.<br />
<br />
Publication: CIL 06, 00499 p 3005, 3757 = CIL 06, 30779c = D 04147 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae Summae Parenti Hermae et Attidi Menotyranno Invicto Clodius Hermogenianus Caesarius vir clarissimus proconsul Africae praefectus urbis Romae XV vir sacris faciundis taurobolio criobolioque perfecto XIIII Kalendas Augustas diis animae suae mentisque custodibus aram dicavit domino nostro Gratiano Augusto tertium et 3 Aequitio conssulibus<br />
<br />
Publication: CIL 06, 00500 p 3005, 3757 = CIL 06, 30779d = D 04148 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno Conservatoribus suis Caelius Hilarianus vir clarissimus duodecimvir urbis Romae pater sacrorum et hieroceryx Invicti Mithrae sacerdos dei Liberi sacerdos deae Hecate domino nostro Gratiano Augusto et Merobaude conssulibus III Idus Maias<br />
<br />
Publication: CIL 06, 00501 p 3005, 3757 = CIL 06, 30779e = D 04149 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Sancto Menotyranno Quintus Clodius Flavianus vir clarissimus pontifex maior XV vir sacris faciundis septemvir epulonum pontifex dei Solis taurobolio criobolioque percepto aram dicavit Nonis Aprilibus FFllavis Merobaude II et Saturnino conssulibus<br />
<br />
Publication: CIL 06, 00508 p 3757 = D 04146 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Potentissimis Dis Matri deum Magnae et Attidi Menotyranno 3 Serapias honesta femina sacrata deum matris et Proserpinae taurobolium criobolium caernophorum perceptum per Flavium Antonium Eustochium sacerdotem Phryges maximus praesentibus et tradentibus cclarissimorum vvirorum ex amplissimo et sanctissimo collegio XV virum sacris faciundis die XIII Kalendas Maias cerealibus ddominis nnostris Constantino Maximo Augusto V et Licinio Iuniori Caesari conssulibus<br />
<br />
Publication: CIL 06, 00511 p 3005 = CLE 01529 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menoturano sacrum nobilis in causis forma celsusque Sabinus hic pater Invicti mystica victor habet sermo duos 3 reservans consimiles aufert3 et veneranda movet Cibeles Triodeia signa augentur meritis simbola tauroboli Rufius Caeionius Caeioni(?) Sabini filius(?) vir classimus pontifex maior hierofanta deae Hecatae augur publicus populi Romani Quiritium pater sacrorum Invicti Mthrae tauroboliatus Matris deum Magnae Idaeae et Attidis Minoturani et aram IIII Idus Martias Gratiano V et Merobaude consulibus dedicabit antiqua generose domo cui regia Vesta pontifici felix sacrato militat igne idem augur triplicis cultor venerande Dianae Persidicique Mithrae antistes Babloniae templi taurobolique simul magni dux mistice sacri<br />
<br />
Publication: AE 1953, 00238 = AE 2000, +00136 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Idaeae et Attidi sancto Menotyranno Alfenius Ceionius Iulianus Kamenius vir clarissimus VII vir epulonum pater et hieroceryx sacrorum Soli Invicti Mithrae hierofanta H{a}ecatae archibucolus dei liberi aram taurobolio criobolioque percepto dicabit! die XIIII Kalendas Augustas domino nostro Gratiano Augusto III et Equitio conssulibus<br />
<br />
Publication: CIL 06, 00512 p 3005, 3757 = CLE +00264 = D 04154 = SIRIS 00447 = RICIS-02, 005010212 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno dis Magnis et Tutatoribus suis Ceionius Rufius Volusianus vir clarissimus et inlustris ex vicario Asiae et Ceioni Rufi Volusiani viri clarissimi et inlustris ex praefecto praetorio et ex praefecto urbi et Caecinae Lollianae clarissimae et inlustris feminae deae Isidis sacerdotis filius iterato viginti annis expletis taurobolii sui aram constituit et consecravit X Kalendas Iunias domino nostro Valentiniano Augusto IIII et Neoterio conssulibus<br />
<br />
Publication: AE 1953, 00237 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Magnae Idaeae et Attidi Menotyranno Sextius Rusticus vir clarissimus et inlustris pater patrum dei Invicti Mithrae<br />
<br />
Publication: AE 1953, 00238 = AE 2000, +00136 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Idaeae et Attidi sancto Menotyranno Alfenius Ceionius Iulianus Kamenius vir clarissimus VII vir epulonum pater et hieroceryx sacrorum Soli Invicti Mithrae hierofanta Haecatae archibucolus dei liberi aram taurobolio criobolioque percepto dicabit! die XIIII Kalendas Augustas domino nostro Gratiano Augusto III et Equitio conssulibus<br />
<br />
Publication: CIL 06, 00499 p 3005, 3757 = CIL 06, 30779c = D 04147 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae Summae Parenti Hermae et Attidi Menotyranno Invicto Clodius Hermogenianus Caesarius vir clarissimus proconsul Africae praefectus urbis Romae XV vir sacris faciundis taurobolio criobolioque perfecto XIIII Kalendas Augustas diis animae suae mentisque custodibus aram dicavit domino nostro Gratiano Augusto tertium et 3 Aequitio conssulibus<br />
<br />
Publication: CIL 06, 00500 p 3005, 3757 = CIL 06, 30779d = D 04148 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno Conservatoribus suis Caelius Hilarianus vir clarissimus duodecimvir urbis Romae pater sacrorum et hieroceryx Invicti Mithrae sacerdos dei Liberi sacerdos deae Hecate domino nostro Gratiano Augusto et Merobaude conssulibus III Idus Maias<br />
<br />
Publication: CIL 06, 00501 p 3005, 3757 = CIL 06, 30779e = D 04149 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Sancto Menotyranno Quintus Clodius Flavianus vir clarissimus pontifex maior XVvir sacris faciundis septemvir epulonum pontifex dei Solis taurobolio criobolioque percepto aram dicavit Nonis Aprilibus FFllavis Merobaude II et Saturnino conssulibus<br />
<br />
Publication: CIL 06, 00508 p 3757 = D 04146 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Potentissimis Dis Matri deum Magnae et Attidi Menotyranno 3 Serapias honesta femina sacrata deum matris et Proserpinae taurobolium criobolium caernophorum perceptum per Flavium Antonium Eustochium sacerdotem Phryges maximus praesentibus et tradentibus cclarissimorum vvirorum ex amplissimo et sanctissimo collegio XV virum sacris faciundis die XIII Kalendas Maias cerealibus ddominis nnostris Constantino Maximo Augusto V et Licinio Iuniori Caesari conssulibus<br />
<br />
Publication: CIL 06, 00511 p 3005 = CLE 01529 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menoturano sacrum nobilis in causis forma celsusque Sabinus hic pater Invicti mystica victor habet sermo duos 3 reservans consimiles aufert et veneranda movet Cibeles Triodeia signa augentur meritis simbola tauroboli Rufius Caeionius Caeioni(?) Sabini filius(?) vir classimus pontifex maior hierofanta deae Hecatae augur publicus populi Romani Quiritium pater sacrorum Invicti Mthrae tauroboliatus Matris deum Magnae Idaeae et Attidis Minoturani et aram IIII Idus Martias Gratiano V et Merobaude consulibus dedicabit antiqua generose domo cui regia Vesta pontifici felix sacrato militat igne idem augur triplicis cultor venerande Dianae Persidicique Mithrae antistes Babloniae templi taurobolique simul magni dux mistice sacri<br />
<br />
Publication: CIL 06, 00512 p 3005, 3757 = CLE +00264 = D 04154 = SIRIS 00447 = RICIS-02, 005010212 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno dis Magnis et Tutatoribus suis Ceionius Rufius Volusianus vir clarissimus et inlustris ex vicario Asiae et Ceioni Rufi Volusiani viri clarissimi et inlustris ex praefecto praetorio et ex praefecto urbi et Caecinae Lollianae clarissimae et inlustris feminae deae Isidis sacerdotis filius iterato viginti annis expletis taurobolii sui aram constituit et consecravit X Kalendas Iunias domino nostro Valentiniano Augusto IIII et Neoterio conssulibus</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/Attis_Sources&diff=3055User:Roger Pearse/Attis Sources2022-02-10T16:09:38Z<p>Roger Pearse: /* Ovid, 1st century AD */</p>
<hr />
<div>These are the sources for our knowledge of Attis.<br />
<br />
=Literary Sources=<br />
<br />
==Herodotus, 5th century BC==<br />
<br />
In [http://www.sacred-texts.com/cla/hh/hh1030.htm Herodotus, book 1, 34-45], there is a rambling story about Atys, son of Croesus, accidentally killed by a spear while hunting. In his Cybele and Attis, M. J. Vermaseren considers whether this is part of the myth of Attis. [http://www.dur.ac.uk/Classics/histos/1998/lewis.html This link] asserts that it is.<br />
<br />
But on looking at the text, the account is very dissimilar from any other account. Does anything but the similarity of name tie the two together?<br />
<br />
==Catullus, 84 BC – ca. 54 BC==<br />
<br />
[http://www.vroma.org/~hwalker/VRomaCatullus/063.html Catullus, Poem 63]:<br />
<br />
<pre><br />
Borne in his swift bark over deep seas,<br />
Attis, when eagerly with speedy foot he reached the Phrygian woodland,<br />
and entered the goddess’ abodes, shadowy, forest-crowned;<br />
there, goaded by raging madness, bewildered in mind,<br />
he cast down from him with sharp flint-stone the burden of his member.<br />
So when she felt her limbs to have lost their manbood,<br />
still with fresh blood dabbling the face of the ground,<br />
swiftly with snowy bands she seized the light timbrel,<br />
your timbrel, Cybele, thy mysteries, Mother,<br />
and shaking with soft fingers the hollow oxhide<br />
thus began she to sing to her companions tremulously:<br />
“Come away, ye Gallae, go to the mountain forests of Cybele together,<br />
together go, wandering herd of the lady of Dindymus,<br />
who swiftly seeking alien homes as exiles,<br />
followed my rule as I led you in my train,<br />
endured the fast-flowing brine and the savage seas,<br />
and unmanned your bodies from utter abhorrence of love,<br />
cheer ye your Lady’s heart with swift wanderings.<br />
Let dull delay depart from your mind; go together, follow<br />
to the Phrygian house of Cybele, to the Phrygian forests of the goddess,<br />
where the noise of cymbals sounds, where timbrels re-echo,<br />
where the Phrygian flute-player blows a deep note on his curved reed,<br />
where the Maenads ivy-crowned toss their heads violently,<br />
where with shrill yells they shake the holy emblems,<br />
where that wandering company of the goddess is wont to rove,<br />
whither for us ’tis meet to hasten with rapid dances.”<br />
So soon as Attis, woman yet no true one, chanted thus to her companions,<br />
the revellers suddenly with quivering tongues yell aloud,<br />
the light timbrel rings again, clash again the hollow cymbals,<br />
swiftly to green Ida goes the rout with hurrying foot.<br />
Then too frenzied, panting, uncertain, wanders, gasping for breath,<br />
attended by the timbrel, Attis, through the dark forests their leader,<br />
as a heifer unbroken starting aside from the burden of the yoke.<br />
Fast follow the Gallae their swift-footed leader.<br />
So when they gained the house of Cybele, faint and weary,<br />
after much toil they take their rest without bread;<br />
heavy sleep covers their eyes with drooping weariness,<br />
the delirious madness of their mind departs in soft slumber.<br />
But when the sun with the flashing eyes of his golden face<br />
lightened the clear heaven, the firm lands, the wild sea,<br />
and chased away the shades of night with eager tramping steeds refreshed,<br />
then Sleep fled from wakened Attis and quickly was gone;<br />
him the goddess Pasithea received in her fluttering bosom.<br />
So after soft slumber, freed from violent madness,<br />
as soon as Attis himself in his heart reviewed his own deed,<br />
and saw with clear mind what lie had lost and where he was,<br />
with surging mind again he sped back to the waves.<br />
There, looking out upon the waste seas with streaming eyes,<br />
thus did she piteously address her country with tearful voice:<br />
” O my country that gavest me life! O my country that barest me!<br />
leaving whom, all wretch! as runaway servants leave their masters,<br />
I have borne my foot to the forests of Ida,<br />
to live among snows and frozen lairs of wild beasts,<br />
and visit in my frenzy all their lurking-dens,<br />
– where then or in what region do I think thy place to be, O my country?<br />
Mine eyeballs unbidden long to turn their gaze to thee<br />
while for a short space my mind is free from wild frenzy.<br />
I, shall I from my own home be borne far away into these forests?<br />
from my country, my possessions, my friends, my parents, shall I be?<br />
absent from the market, the wrestling-place, the racecourse, the playground?<br />
unhappy, all unhappy heart, again, again must thou complain.<br />
For what form of human figure is there which I had not?<br />
I, to be a woman–who was a stripling, I a youth, I a boy,<br />
I was the flower of the playground, I was once the glory of the palaestra:<br />
mine were the crowded doorways, mine the warm thresholds,<br />
mine the flowery garlands to deck my house<br />
when I was to leave my chamber at sunrise.<br />
I, shall I now be called–what? a handmaid of the gods, a ministress of Cybele?<br />
I a Maenad, I part of myself, a barren man shall I be?<br />
I, shall I dwell in icy snow-clad regions of verdant Ida,<br />
I pass my life under the high summits of Phrygia,<br />
with the hind that haunts the woodland, with the boar that ranges the forest?<br />
now, now I rue my deed, now, now I would it were undone.”<br />
From his rosy lips as these words issued forth,<br />
bringing a new message to both ears of the gods,<br />
then Cybele, loosening the fastened yoke from her lions,<br />
and goading that foe of the herd who drew on the left, thus speaks:<br />
“Come now,” she says, “come, go fiercely, let madness hunt him hence<br />
bid him hence by stroke of madness hie him to the forests again,<br />
him who would be too free, and run away from my sovereignty.<br />
Come, lash back with tail, endure thy own scourging,<br />
make all around resound with bellowing roar,<br />
shake fiercely on brawny neck thy ruddy mane.”<br />
Thus says wrathful Cybele, and with her hand unbinds the yoke.<br />
The monster stirs his courage and rouses him to fury of heart;<br />
he speeds away, he roars, with ranging foot he breaks the brushwood.<br />
But when he came to the watery stretches of the white-gleaming shore,<br />
and saw tender Attis by the smooth spaces of the sea,<br />
he rushes at him–madly flies Attis to the wild woodland.<br />
There always for all his lifetime was he a handmaid.<br />
Goddess, great goddess, Cybele, goddess, lady of Dindymus<br />
far from my house be all thy fury, O my queen<br />
others drive thou in frenzy, others drive thou to madness.<br />
</pre><br />
<br />
==Diodorus Siculus, 1st century BC==<br />
<br />
[http://penelope.uchicago.edu/Thayer/E/Roman/Texts/Diodorus_Siculus/3D*.html Diodorus Siculus, History, 3.58.4-59.1]:<br />
<br />
58. However, an account is handed down also that this goddess was born in Phrygia. For the natives of that country have the following myth: In ancient times Meïon became king of Phrygia and Lydia; and marrying Dindymê he begat an infant daughter, but being unwilling to rear her he exposed her on the mountain which was called Cybelus. There, in accordance with some divine providence, both the leopards and some of the other especially ferocious wild beasts offered their nipples to the child and so gave it nourishment, and some women who were tending the flocks in that place witnessed the happening, and being astonished at the strange event took up the babe and called her Cybelê after the name of the place. The child, as she grew up, excelled in both beauty and virtue and also came to be admired for her intelligence; for she was the first to devise the pipe of many reeds and to invent cymbals and kettledrums with which to accompany the games and the dance, and in addition she taught how to heal the sicknesses of both flocks and little children by means of rites of purification; in consequence, since the babes were saved from death by her spells and were generally taken up in her arms, her devotion to them and affection for them led all the people to speak of her as the “mother of the mountain.” The man who associated with her and loved her more than anyone else, they say, was Marsyas the physician, who was admired for his intelligence and chastity; and a proof of his intelligence they find in the fact that he imitated the sounds made by the pipe of many reeds and carried all its notes over into the flute, and as an indication of his chastity they cite his abstinence from sexual pleasures until the day of his death.<br />
<br />
Now Cybelê, the myth records, having arrived at full womanhood, came to love a certain native youth who was known as Attis, but at a later time received the appellation Papas; with him she consorted secretly and became with child, and at about the same time her parents recognized her as their child. Consequently she was brought up into the palace, and her father welcomed her at the outset under the impression the she was a virgin, but later, when he learned of her seduction, he put to death her nurses and Attis as well and cast their bodies forth to lie unburied; whereupon Cybelê, they say, because of her love for the youth and grief over the nurses, became frenzied and rushed out of the palace into the countryside. And crying aloud and beating upon a kettledrum she visited every country alone, with hair hanging free, and Marsyas, out of pity for her plight, voluntarily followed her and accompanied her in her wanderings because of the love which he had formerly borne her. … And Apollo, they say, laid away both the lyre and the pipes as a votive offering in the cave of Dionysus, and becoming enamoured of Cybelê joined in her wanderings as far as the land of the Hyperboreans.<br />
<br />
But, the myth goes on to say, a pestilence fell upon human beings throughout Phrygia and the land ceased to bear fruit, and when the unfortunate people inquired of the god how they might rid themselves of their ills he commanded them, it is said, to bury the body of Attis and to honour Cybelê as a goddess. Consequently the physicians, since the body had disappeared in the course of time, made an image of the youth, before which they sang dirges and by means of honours in keeping with his suffering propitiated the wrath of him who had been wronged; and these rites they continue to perform down to our own lifetime. As for Cybelê, in ancient times they erected altars and performed sacrifices to her yearly; and later they built for her a costly temple in Pisinus of Phrygia, and established honours and sacrifices of the greatest magnificence, Midas their king taking part in all these works out of his devotion to beauty; and beside the statue of the goddess they set up panthers and lions, since it was the common opinion that she had first been nursed by these animals.<br />
<br />
Such, then, are the myths which are told about Mother of the God both among the Phrygians and by the Atlantians who dwell on the coast of the ocean.<br />
<br />
==Ovid, 1st century AD==<br />
<br />
[http://www.tkline.freeserve.co.uk/OvidFastiBkFour.htm Ovid, Fasti, 4.221-224]:<br />
<br />
<pre><br />
… I said ‘Where did this urge to cut off<br />
Their members come from?’ As I ended, the Muse spoke:<br />
‘In the woods, a Phrygian boy, Attis, of handsome face,<br />
Won the tower-bearing goddess with his chaste passion.<br />
She desired him to serve her, and protect her temple,<br />
And said: “Wish, you might be a boy for ever.”<br />
He promised to be true, and said: “If I’m lying<br />
May the love I fail in be my last love.”<br />
He did fail, and in meeting the nymph Sagaritis,<br />
Abandoned what he was: the goddess, angered, avenged it.<br />
She destroyed the Naiad, by wounding a tree,<br />
Since the tree contained the Naiad’s fate.<br />
Attis was maddened, and thinking his chamber’s roof<br />
Was falling, fled for the summit of Mount Dindymus.<br />
Now he cried: “Remove the torches”, now he cried:<br />
“Take the whips away”: often swearing he saw the Furies.<br />
He tore at his body too with a sharp stone,<br />
And dragged his long hair in the filthy dust,<br />
Shouting: “I deserved this! I pay the due penalty<br />
In blood! Ah! Let the parts that harmed me, perish!<br />
Let them perish!” cutting away the burden of his groin,<br />
And suddenly bereft of every mark of manhood.<br />
His madness set a precedent, and his unmanly servants<br />
Toss their hair, and cut off their members as if worthless.’<br />
So the Aonian Muse, eloquently answering the question<br />
I’d asked her, regarding the causes of their madness.<br />
</pre><br />
<br />
[https://ovid.lib.virginia.edu/trans/Metamorph10.htm#484521419 Ovid, Metamorphoses (X.103-5)]:<br />
<br />
<pre><br />
You came, also, ... the pliant palms, the winner’s prize; and you, the shaggy-topped pine tree, armed with needles, <br />
sacred to Cybele, mother of the gods, since Attis exchanged his human form for you, and hardened in your trunk.<br />
</pre><br />
<br />
==Pausanias, 2nd century AD==<br />
<br />
[http://books.google.co.uk/books?dq=pausanias+description+of+greece&pg=PA191&id=p6oAAAAAYAAJ&ots=mmAB61GsT0 Pausanius, Guide to Greece, 7.17.5]:<br />
<br />
The Achaian city Dyme is distant about four hundred stadia from Larissus… Besides this the Dymaei have a temple of Minerva, and a statue of the goddess, which is very ancient. They have also another temple sacred to the mother Dindymene, and Attes. But who Attes is, I have not been able to discover, because it is. an arcane affair. Hermesianax, indeed, a writer of elegies, says, that he was the son of the Phrygian Calaus, and that he was produced by his mother incapable of begetting children. That when he arrived at manhood he migrated to Lydia, and established there the orgies of the Great Mother. And that he was so highly honoured by the goddess, that it excited the indignation of Jupiter, who sent a boar into the Lydian fields, by which other Lydians were destroyed, and Attes himself was slain. The Gauls who inhabit Pesinus, confirm by their conduct the truth of this relation, for they cannot bear to touch swine. However, they report things concerning Attes far different from the above.<br />
<br />
Jupiter, say they, while he was asleep emitted his seed on the earth; this in process of time produced a daemon with twofold private parts, viz. with the parts of man and woman united. The name of this daemon was Agdistis: and the gods, in consequence of being terrified at him, cut off his virile parts. From these parts an almond tree was produced, the fruit of which, when ripe, the daughter of the river Sangarius gathered and concealed in her bosom. The fruit, however, immediately vanished, and she became pregnant. As the result of her pregnancy, she was delivered of a boy, who being left in the woods was educated by a goat, and who, as he grew in years, possessed a beauty surpassing that of the human form, and through which Agdistis fell in love with him. But when he arrived at manhood, his friends sent him to Pesinus, in order that he might marry the daughter of the king. Here, as they were singing the nuptial song, Agdistis presented himself before them, and Attes becoming insane, cut off his private parts. The king’s daughter, too, that was given to Attes, cut off her privities. But Agdistis was grieved that Attes had acted in this manner, and obtained of Jupiter that no part of the body of Attes should either become putrid or waste away. And such are the particulars which are reported about Attes.<br />
<br />
==Lucian, 2nd century AD==<br />
<br />
[http://www.sacred-texts.com/cla/luc/tsg/tsg07.htm Lucian, ''De Dea Syria''. Chapters. 50-51]:<br />
<br />
50. On certain days a multitude flocks into the temple, and the Galli in great numbers, sacred as they are, perform the ceremonies of the men and gash their arms and turn their backs to be lashed. Many bystanders play on the pipes the while many beat drums; others sing divine and sacred songs. All this performance takes place outside the temple, and those engaged in the ceremony enter not into the temple.<br />
<br />
51. During these days they are made Galli. As the Galli sing and celebrate their orgies, frenzy falls on many of them and many who had come as mere spectators afterwards are found to have committed the great act. I will narrate what they do. Any young man who has resolved on this action, strips off his clothes, and with a loud shout bursts into the midst of the crowd, and picks up a sword from a number of swords which I suppose have been kept ready for many years for this purpose. He takes it and castrates himself and then runs wild through the city, bearing in his hands what he has cut off. He casts it into any house at will, and from this house he receives women’s raiment and ornaments. Thus they act during their ceremonies of castration.<br />
<br />
52. The Galli, when dead, are not buried like other men, but when a Gallus dies his companions carry him out into the suburbs, and laying him out on the bier on which they had carried him they cover him with stones, and after this return home. They wait then for seven days, after which they enter the temple. Should they enter before this they would be guilty of blasphemy.<br />
<br />
(There is a question whether this rite relates to Cybele and Attis, depending on whether we identify the Syrian goddess with Cybele.)<br />
<br />
==Arnobius, 3-4th century AD==<br />
<br />
[http://www.tertullian.org/fathers2/ANF-06/anf06-138.htm#P7705_2431814 Arnobius the Elder, Against the Pagans, book 5, 5-7]:<br />
<br />
5. In Timotheus, who was no mean mythologist, and also in others equally well informed, the birth of the Great Mother of the gods, and the origin of her rites, are thus detailed, being derived-as he himself writes and suggests-from learned books of antiquities, and from his acquaintance with the most secret mysteries:-<br />
<br />
Within the confines of Phrygia, he says, there is a rock of unheard-of wildness in every respect, the name of which is Agdus, so named by the natives of that district. Stones taken from it, as Themis by her oracle had enjoined, Deucalion and Pyrrha threw upon the earth, at that time emptied of men; from which this Great Mother, too, as she is called, was fashioned along with the others, and animated by the deity. Her, given over to rest and sleep on the very summit of the rock, Jupiter assailed with lewdest desires. But when, after long strife, he could no accomplish what he had proposed to himself, he, baffled, spent his lust on the stone. This the rock received, and with many groanings Acdestis is born in the tenth month, being named from his mother rock.<br />
<br />
In him there had been resistless might, and a fierceness of disposition beyond control, a lust made furious, and derived from both sexes. He violently plundered and laid waste; he scattered destruction wherever the ferocity of his disposition had led him; he regarded not gods nor men, nor did he think anything more powerful than himself; he contemned earth, heaven, and the stars.<br />
<br />
6. Now, when it had been often considered in the councils of the gods, by what means it might be possible either to weaken or to curb his audacity, Liber, the rest hanging back, takes upon himself this task. With the strongest wine he drugs a spring much resorted to by Acdestis where he had been wont to assuage the heat and burning thirst roused in him by sport and hunting. Hither runs Acdestis to drink when he felt the need; he gulps down the draught too greedily into his gaping veins. Overcome by what he is quite unaccustomed to, he is in consequence sent fast asleep.<br />
<br />
Liber is near the snare which he had set; over his foot he throws one end of a halter formed of hairs, woven together very skilfully; with the other end he lays hold of his privy members. When the fumes of the wine passed off, Acdestis starts up furiously, and his foot dragging the noose, by his own strength he robs himself of his sex; with the tearing asunder of these parts there is an immense flow of blood; both are carried off and swallowed up by the earth; from them there suddenly springs up, covered with fruit, a pomegranate tree, seeing the beauty of which, with admiration, Nana, daughter of the king or river Sangarius, gathers and places in her bosom some of the fruit.<br />
<br />
By this she becomes pregnant; her father shuts her up, supposing that she had been debauched, and seeks to have her starved to death; she is kept alive by the mother of the gods with apples, and other food, and brings forth a child, but Sangarius orders it to be exposed.<br />
<br />
One Phorbas having found the child, takes it home, brings it up on goats’ milk; and as handsome fellows are so named in Lydia, or because the Phrygians in their own way of speaking call their goats attagi, it happened in consequence that the boy obtained the name Attis.<br />
<br />
Him the mother of the gods loved exceedingly, because he was of most surpassing beauty; and Acdestis, who was his companion, as he grew up fondling him, and bound to him by wicked compliance with his lust in the only way now possible, leading him through the wooded glades, and presenting him with the spoils of many wild beasts, which the boy Attis at first said boastfully were won by his own toil and labour. Afterwards, under the influence of wine, he admits that he is both loved by Acdestis, and honoured by him with the gifts brought from the forest; whence it is unlawful for those polluted by drinking wine to enter into his sanctuary, because it discovered his secret.<br />
<br />
7. Then Midas, king of Pessinus, wishing to withdraw the youth from so disgraceful an intimacy, resolves to give him his own daughter in marriage, and caused the gates of the town to be closed, that no one of evil omen might disturb their marriage joys.<br />
<br />
But the mother of the gods, knowing the fate of the youth, and that he would live among men in safety only so long as he was free from the ties of marriage, that no disaster might occur, enters the closed city, raising its walls with her head, which began to be crowned with towers in consequence. Acdestis, bursting with rage because of the boy’s being torn from himself, and brought to seek a wife, fills all the guests with frenzied madness: the Phrygians shriek aloud, panic-stricken at the appearance of the gods; a daughter of adulterous Gallus cuts off her breasts; Attis snatches the pipe borne by him who was goading them to frenzy; and he, too, now filled with furious passion, raving frantically and tossed about, throws himself down at last, and under a pine tree mutilates himself, saying, “Take these, Acdestis, for which you have stirred up so great and terribly perilous commotions.”<br />
<br />
With the streaming blood his life flies; but the Great Mother of the gods gathers the parts which had been cut off, and throws earth on them, having first covered them, and wrapped them in the garment of the dead. From the blood which had flowed springs a flower, the violet, and with this the tree is girt. Thence the custom began and arose, whereby you even now veil and wreath with flowers the sacred pine.<br />
<br />
The virgin who had been the bride, whose name, as Valerius the pontifex relates, was Ia, veils the breast of the lifeless youth with soft wool, sheds tears with Acdestis, and slays herself After her death her blood is changed into purple violets.<br />
<br />
The mother of the gods sheds tears also, from which springs an almond tree, signifying the bitterness of death. Then she bears away to her cave the pine tree, beneath which Attis had unmanned himself; and Acdestis joining in her wailings, she beats and wounds her breast, pacing round the trunk of the tree now at rest.<br />
<br />
Jupiter is begged by Acdestis that Attis may be restored to life: he does not permit it. What, however, fate allowed, he readily grants, that his body should not decay, that his hairs should always grow, that the least of his fingers should live, and should be kept ever in motion; content with which favours, it is said that Acdestis consecrated the body in Pessinus, and honoured it with yearly rites and priestly services.<br />
<br />
And:<br />
<br />
16. And yet how can you assert the falsehood of this story, when the very rites which you celebrate throughout the year testify that you believe these things to be true, and consider them perfectly trustworthy?<br />
<br />
For what is the meaning of that pine which on fixed days you always bring into the sanctuary of the mother of the gods? Is it not in imitation of that tree, beneath which the raging and ill-fated youth laid hands upon himself, and which the parent of the gods consecrated to relieve her sorrow?<br />
<br />
What mean the fleeces of wool with which you bind and surround the trunk of the tree? Is it not to recall the wools with which Ia covered the dying youth, and thought that she could procure some warmth for his limbs fast stiffening with cold? What mean the branches of the tree girt round and decked with wreaths of violets? Do they not mark this, how the Mother adorned with early flowers the pine which indicates and bears witness to the sad mishap?<br />
<br />
What mean the Galli with dishevelled hair beating their breasts with their palms? Do they not recall to memory those lamentations with which the tower-bearing Mother, along with the weeping Acdestis, wailing aloud, followed the boy? What means the abstinence from eating bread which you have named castus? Is it not in imitation of the time when the goddess abstained from Ceres’ fruit in her vehement sorrow?<br />
<br />
17. Or if the things which we say are not so declare, say yourselves-those effeminate and delicate men whom we see among you in the sacred rites of this deity-what business, what care, what concern have they there; and why do they like mourners wound their arms and breasts, and act as those dolefully circumstanced?<br />
<br />
What mean the wreaths, what the violets, what the swathings, the coverings of soft wools? Why, finally, is the very pine, but a little before swaying to and fro among the shrubs, an utterly inert log, set up in the temple of the Mother of the gods next, like some propitious and very venerable deity?<br />
<br />
For either this is the cause which we have found in your writings and treatises, and in that case it is clear that you do not celebrate divine rites, but give a representation of sad events; or if there is any other reason which the darkness of the mystery has withheld from us, even it also must be involved in the infamy of some shameful deed. For who would believe that there is any honour in that which the worthless Galli begin, effeminate debauchees complete?<br />
<br />
And ch. 39:<br />
<br />
39. Whence, then, do we prove that all these narratives are records of events? Froth the solemn rites and mysteries of initiation, it is clear, whether those which are celebrated at fixed times and on set days, or those which are taught secretly by the heathen without allowing the observance of their usages to be interrupted.<br />
<br />
For it is not to be believed that these have no origin, are practised without reason or meaning, and have no causes connected with their first beginnings. That pine which is regularly born into the sanctuary of the Great Mother, is it not in imitation of that tree beneath which Attis mutilated and unmanned himself, which also, they relate, the goddess consecrated to relieve her grief? That erecting of phalli and fascina, which Greece worships and celebrates in rites every year, does it not recall the deed by which Liber paid his debt?<br />
<br />
==Firmicus Maternus, ca. 350 AD==<br />
<br />
[http://www.roger-pearse.com/weblog/?p=1433 Firmicus Maternus, De errore profanum religionum, chap. 3]<br />
<br />
III. (1) The Phyrgians who live at Pessinus around the banks of the river Gallus, assign first place to the earth over the other elements, and this they profess (volunt) is the mother of all things. Then, so that they also might have for themselves an order of annual sacred events, they have consecrated the love affair of a rich women, their queen, who chose to punish tyrannically the scorn of an adolescent lover, with annual lamentations. And to satisfy the irate woman, or to find consolation for her remorse, he whom they had buried a little earlier, they claim that he had come back to life. And as the soul of the woman burned with the impatience of excessive love, they built temples to the dead youth. Then they profess that the priests appointed should undergo from themselves what the angry woman had done because of the injury to her scorned beauty. So in the annual sacred rites in honour of the earth the pomp of his funeral is organised, and when men are persuaded that they are honouring the earth, they are (in fact) venerating the death and funeral of a wretch.<br />
<br />
(2) Here also, most sacred emperors, in order to shield this error, they profess that these natural sacred rites are also arranged rationally. They profess that the earth loves its fruits, they profess that Attis is exactly this, which is born from fruits; however the punishment which he sustained, this they profess is what the reaper with his scythe does to the ripe fruits. They call it his death when the collected seeds are stored; life again, when the sown seeds sprout in the turning of the years.<br />
<br />
(3) I would like them now to reply to my inquiry, why have they associated this simple (story of) seed and fruit with a funeral, with death, with scorn, with punishment, with love? Was there not anything else that might be said? Was there not anything else that poor mortals might do in grateful thanks to the highest God for the crop? So that you can give thanks for the reborn crop, you howl; so that you rejoice, you weep. And you, when you see the true reason, you do not finally repent of doing this, but you do this, so that busyied with the turning seasons, you still flee from life, you pine for death.<br />
<br />
(4) Let them tell me, how it benefits the crop, that they renew their tears with yearly howlings, that they groan over the calamities of a reborn corpse, which they say is arranged for a natural reason. You mourn and you wail, and you cover your mourning with another excuse. The farmer knew when he could furrow the earth with a plow, when he could sow the furrows with grain, he knew when to gather the crop ripened by the heat of the sun, he knew when to tread out the dried crop. This is the natural reason, these are the true sacrificial rites, which are carried out by the yearly labour in men of healthy minds. The divinity asks for this simplicity, that men should follow the laws ordained of the seasons (temporum) in collecting crops. Why do they try to explain this order by wretched fictions of a death? Why is that shielded with tears, which does not need to be shielded? From which let them admit of necessity, that these rites are not held in honour of the crops, but in honour of an unworthy death.<br />
<br />
(5) When they say that the earth is the mother of all the gods, and they allot the chief roles to this element, indeed it is mother of their gods, — this we don’t deny or refuse, because from it they are always making their bunch of gods, whether of stone or wood. The sea flows around the whole earth, and again it is held tight by the circle of the encircling embracing Ocean. The heavens also are covered by the lofty dome, blown through by winds, splashed by rains, and in fear, as shown by tremors of unremitting motion. What remains to you, who cultivate these things, consider; when your gods reveal their weakness to you in daily declarations.<br />
<br />
==Julian the Apostate, 363 AD==<br />
<br />
[http://www.tertullian.org/fathers2/NPNF1-02/npnf1-02-12.htm#P1101_586858 Julian, Oratio 5: on the Magna Mater]:<br />
<br />
Who then is the Mother of the Gods? She is the Source of the Intelligible and Creative Powers, which direct the visible ones; she that gave birth to and copulated with the mighty Jupiter: she that exists as a great goddess next to the Great One, and in union with the Great Creator; she that is dispenser of all life; cause of all birth; most easily accomplishing all that is made; generating without passion; creating all that exists in concert with the Father; herself a virgin, without mother, sharing the throne of Jupiter, the mother in very truth of all the gods; for by receiving within herself the causes of all the intelligible deities that be above the world, she became the source to things the objects of intellect.<br />
<br />
Now this goddess, who is also the same as Providence, was seized with a love without passion for Attis. … And this the legend aims at teaching when it makes the Mother of the Gods enjoin upon Attis to be her servant, and not to stray from her, and not fall in love with another woman. But he went forward, and descended as far as the boundaries of Matter.<br />
<br />
But when it became necessary for this ignorance to cease and be stopped—-then Corybas, the mighty Sun, the colleague of the Mother of the Gods … persuades the lion to turn informer. Who then is this lion? We hear him styled “blazing”—-he must, therefore, I think, be the cause presiding over the hot and fiery element; that which was about to wage war against the Nymph, and to make her jealous of her intercourse with Attis; and who this Nymph is we have already stated.<br />
<br />
This lion, the fable tells, lent his aid to the Mother of the Gods … and by his detecting the offence and turning informer, became the author of the castration of the youth. … not without the intervention of the fabled madness of Attis…<br />
<br />
It is not therefore unreasonable to suppose this Attis a sixper-natural personage (in fact the fable implies as much), or rather in all respects, a deity, seeing that he comes forth out of the Third Creator, and returns again after his castration, to the Mother of the Gods… the fable styles him a “demi-god,” … The Corybantes… are assigned by the Great Mother to act as his bodyguard…<br />
<br />
This great god of ours is Attis; this is the meaning of the “Flight of King Attis” that we have just been lamenting; his “Concealments,” his “Vanishings,” his “Descents into the Cave.” Let my evidence be the time of year when all these ceremonies take place; for it is said that the Sacred Tree is cut down at the moment when the Sun arrives at the extreme point of the equinoctial arc: next in order follows the Sounding of the trumpets, and lastly is cut down the sacred and ineffable Harvest of the god Gallos: after these come, as they say, the Hilaria and festivities.<br />
<br />
Now that a “cessation of Indefinity” is meant by the castration so much talked of by the vulgar, is self-evident from the fact that when the Sun touches the equinoctial circle, where that which is most definite is placed (for equality is definite, but inequality indefinite and inexplicable); at that very moment (according to the report), the Sacred Tree is cut down; then come the other rites in their order; whereof some are done in compliance with rules that be holy and not to be divulged; others for reasons allowable to be discussed.<br />
<br />
The “Cutting of the Tree;” this part refers to the legend about the Gallos, and has nothing to do with the rites which it accompanies… The rite, therefore, enjoins upon us who are celestial by our nature, but who have been carried down to earth, to reap virtue joined with piety from our conduct upon earth, and to aspire upwards unto the deity, the primal source of being and the fount of life. Then immediately after the cutting does the trumpet give out the invocation to Attis and to those that be of heaven, whence we took our flight, and fell down to earth.<br />
<br />
And after this, when King Attis checks the Indefinity by the means of castration, the gods thereby warn us to extirpate in ourselves all incontinence, and to imitate the example, and to run upwards unto the Definite, and the Uniform, and if it be possible, to the One itself; which being accomplished the “Hilaria” must by all means follow. For what could be more contented, what more hilarious than the soul that has escaped from uncertainty, and generation, and the tumult that reigns therein, and hastens upwards to the gods? Of whose number was this Attis, whom the Mother of the Gods would not suffer to advance farther than was proper for him, but turned him towards herself, and enjoined him to check all indefinity.<br />
<br />
==Sallustius, mid-4th century AD==<br />
<br />
[http://www.sacred-texts.com/cla/fsgr/fsgr10.htm Sallustius, ''De diis et mundo''] - This is the Gilbert Murray 1925 translation, published as an appendix to "Five stages of Greek religion" and appearing on Sacred Texts. There is also an A.D.Nock 1926 translation, and there is an old one somewhere by Thomas Taylor. Sallustius was a friend of Julian the Apostate.<br />
<br />
To take another myth, they say that the Mother of the Gods seeing Attis lying by the river Gallus fell in love with him, took him, crowned him with her cap of stars, and thereafter kept him with her. He fell in love with a nymph and left the Mother to live with her. For this the Mother of the Gods made Attis go mad and cut off his genital organs and leave them with the nymph, and then return and dwell with her.<br />
<br />
Now the Mother of the Gods is the principle that generates life; that is why she is called Mother. Attis is the creator of all things which are born and die; that is why he is said to have been found by the river Gallus. For Gallus signifies the Galaxy, or Milky Way, the point at which body subject to passion begins. Now as the primary gods make perfect the secondary, the Mother loves Attis and gives him celestial powers.<br />
<br />
That is what the cap means. Attis loves a nymph: the nymphs preside over generation, since all that is generated is fluid. But since the process of generation must be stopped somewhere, and not allowed to generate something worse than the worst, the creator who makes these things casts away his generative powers into the creation and is joined to the Gods again. Now these things never happened, but always are. And mind sees all things at once, but reason (or speech) expresses some first and others after. Thus, as the myth is in accord with the cosmos, we for that reason keep a festival imitating the cosmos, for how could we attain higher order?<br />
<br />
==Anonymous, Carmen Ad Antonium, early 5th century (?)==<br />
<br />
[http://www.roger-pearse.com/weblog/?p=4402 here].<br />
<br />
Why do they hope for anything from Jupiter who came second after this king yet who is served with offerings through the lips of suppliants? This god has a mother, too, who was overtaken by love for a shepherd, so the shepherd himself came before Jupiter or Jove; but the shepherd was his superior for, wishing to preserve his chastity, he rejected the goddess who in her rage castrated him so that he who had refused to come to her bed should never be the husband of another. Was this the just ordinance of the gods however, that a man who had not been made a fornicator should never be a husband? Now, too, eunuchs chant shameful mysteries nor are there lacking men to be corrupted by this infection. They worship some secret the more profound for being behind closed doors and call holy something which would render a modest man unholy should he approach it. Thus the priest himself, more restricted, avoids sleeping with women and accepts the embrace of men.<br />
<br />
==Augustine, early 5th century AD==<br />
<br />
[http://www.tertullian.org/fathers2/NPNF1-02/npnf1-02-12.htm#P1101_586858 Augustine, City of God, book 6, chapter 7]:<br />
<br />
There are sacred rites of the mother of the gods, in which the beautiful youth Atys, loved by her, and castrated by her through a woman’s jealousy, is deplored by men who have suffered the like calamity, whom they call Galli. …<br />
<br />
What good is to be thought of their sacred rites which are concealed in darkness, when those which are brought forth into the light are so detestable? And certainly they themselves have seen what they transact in secret through the agency of mutilated and effeminate men. Yet they have not been able to conceal those same men miserably and vile enervated and corrupted.<br />
<br />
Let them persuade whom they can that they transact anything holy through such men, who, they cannot deny, are numbered, and live among their sacred things. We know not what they transact, but we know through whom they transact; for we know what things are transacted on the stage, where never, even in a chorus of harlots, hath one who is mutilated or an effeminate appeared.<br />
<br />
And, nevertheless, even these things are acted by vile and infamous characters; for, indeed, they ought not to be acted by men of good character. What, then, are those sacred rites, for the performance of which holiness has chosen such men as not even the obscenity of the stage has admitted?<br />
<br />
==Proclus, 5th century==<br />
<br />
[http://www.tertullian.org/fathers/marinus_01_life_of_proclus.htm Marinus, Life of Proclus, ch. 33]<br />
<br />
33. But if I was to enumerate all the facts of this kind, and to report the particular devotion which he held for Pan, son of Hermes, the great favors he received, and the numerous times he was, in Athens, saved by intervention of the divinity, and to relate in detail the protections and the advantages he received from the Mother of the Gods, of which he was particularly proud and happy, I would no doubt seem chattering vainly, to those who may light on this book by chance, and some may even think I am saying things little worthy of belief. For there were a considerable number of episodes, that were of almost daily occurrence, when this goddess [Cybele] spoke or acted in his favor; and their number and character are so unusual that I myself do not have their exact and precise memory.<br />
<br />
If anyone desires to know with what favor he was attached to this goddess, let him read Proclus's book on the Mother of the Gods, and it will be seen that with inspiration from on high he has been able to expound the whole theology relative to the goddess, and to explain philosophically all that the liturgical actions and the oral instructions mythically teach us about the goddess, and Attis, so that they will no longer be troubled by those seemingly absurd lamentations [for Attis] and all the secret traditions related in her ceremonies.<br />
<br />
==Damascius, early 6th century AD==<br />
<br />
From ''Life of Isidore'', as quoted by Photius, ''Bibliotheca'', codex 242.<br />
<br />
131. At Hierapolis in Phrygia there is a temple of Apollo and under the temple a subterranean fissue descends, which exhales lethal vapours. It is impossible to pass this gulf without danger, even for birds, and everyone who enters it dies. But the author says that it is possible for initiates to descend into the crevasse itself and stay there without injury. The author says that he himself and the philosopher Dorus, led by curiosity, descended into it and returned unharmed. The author says, “I then slept at Hierapolis and in a dream it seemed to me that I was Attis and that, by the order of the Great Mother of the gods, I was celebrating what is called the festival of the Hilaria; this dream signified our liberation from Hades. On returning to Aphrodisias, I recounted to Asclepiodotus the vision that I had in the dream. And he, full of admiration for what had happened to me, recounted to me, not “a dream for a dream”, but a great marvel in exchange for a little one.<br />
<br />
He said in fact that in his youth he had gone to that place to study the nature of it. He had rolled his mantle two and three times around his nostrils so that in the event of frequent fumes, he could breathe not the poisoned and deleterious air but pure and safe air which he had brought with him captured in his mantle. Proceeding thus, he entered on the descent, following a current of hot water which came out from there, and ran the length of the inaccessible crevasse. All the same he didn’t get to the bottom of the descent, because the access to it was cut off by the abundance of water and the passage was impossible to an ordinary man, but the one descending, possessed by the divinity, was carried to the bottom. Asclepiodotus then climbed back up from that place without injury thanks to his ingenuity. Later he even tried to recreate the lethal air using various ingredients.<br />
<br />
== John the Lydian ==<br />
<br />
''De Mensibus'' IV.41 reads:<br />
<br />
On day 11, the kalends of April, a pine tree is carried into the Palatine by the tree-bearers. But the emperor Claudius instituted these these ferias, a man of such justice in judgement that...<br />
<br />
=Inscriptions=<br />
<br />
The Clauss-Slaby database records a considerable number of inscriptions that mention Attis.<br />
<br />
==Attis Menotyrannus==<br />
<br />
In the following inscriptions, all from Rome and nowhere else, Attis is labelled "Menotyrannus". This may mean "Lord of the months", or derive from Men, the Phygian moon-god.<br />
<br />
Publication: CIL 06, 00499 p 3005, 3757 = CIL 06, 30779c = D 04147 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae Summae Parenti Hermae et Attidi Menotyranno Invicto Clodius Hermogenianus Caesarius vir clarissimus proconsul Africae praefectus urbis Romae XV vir sacris faciundis taurobolio criobolioque perfecto XIIII Kalendas Augustas diis animae suae mentisque custodibus aram dicavit domino nostro Gratiano Augusto tertium et 3 Aequitio conssulibus<br />
<br />
Publication: CIL 06, 00500 p 3005, 3757 = CIL 06, 30779d = D 04148 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno Conservatoribus suis Caelius Hilarianus vir clarissimus duodecimvir urbis Romae pater sacrorum et hieroceryx Invicti Mithrae sacerdos dei Liberi sacerdos deae Hecate domino nostro Gratiano Augusto et Merobaude conssulibus III Idus Maias<br />
<br />
Publication: CIL 06, 00501 p 3005, 3757 = CIL 06, 30779e = D 04149 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Sancto Menotyranno Quintus Clodius Flavianus vir clarissimus pontifex maior XV vir sacris faciundis septemvir epulonum pontifex dei Solis taurobolio criobolioque percepto aram dicavit Nonis Aprilibus FFllavis Merobaude II et Saturnino conssulibus<br />
<br />
Publication: CIL 06, 00508 p 3757 = D 04146 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Potentissimis Dis Matri deum Magnae et Attidi Menotyranno 3 Serapias honesta femina sacrata deum matris et Proserpinae taurobolium criobolium caernophorum perceptum per Flavium Antonium Eustochium sacerdotem Phryges maximus praesentibus et tradentibus cclarissimorum vvirorum ex amplissimo et sanctissimo collegio XV virum sacris faciundis die XIII Kalendas Maias cerealibus ddominis nnostris Constantino Maximo Augusto V et Licinio Iuniori Caesari conssulibus<br />
<br />
Publication: CIL 06, 00511 p 3005 = CLE 01529 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menoturano sacrum nobilis in causis forma celsusque Sabinus hic pater Invicti mystica victor habet sermo duos 3 reservans consimiles aufert3 et veneranda movet Cibeles Triodeia signa augentur meritis simbola tauroboli Rufius Caeionius Caeioni(?) Sabini filius(?) vir classimus pontifex maior hierofanta deae Hecatae augur publicus populi Romani Quiritium pater sacrorum Invicti Mthrae tauroboliatus Matris deum Magnae Idaeae et Attidis Minoturani et aram IIII Idus Martias Gratiano V et Merobaude consulibus dedicabit antiqua generose domo cui regia Vesta pontifici felix sacrato militat igne idem augur triplicis cultor venerande Dianae Persidicique Mithrae antistes Babloniae templi taurobolique simul magni dux mistice sacri<br />
<br />
Publication: AE 1953, 00238 = AE 2000, +00136 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Idaeae et Attidi sancto Menotyranno Alfenius Ceionius Iulianus Kamenius vir clarissimus VII vir epulonum pater et hieroceryx sacrorum Soli Invicti Mithrae hierofanta H{a}ecatae archibucolus dei liberi aram taurobolio criobolioque percepto dicabit! die XIIII Kalendas Augustas domino nostro Gratiano Augusto III et Equitio conssulibus<br />
<br />
Publication: CIL 06, 00512 p 3005, 3757 = CLE +00264 = D 04154 = SIRIS 00447 = RICIS-02, 005010212 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno dis Magnis et Tutatoribus suis Ceionius Rufius Volusianus vir clarissimus et inlustris ex vicario Asiae et Ceioni Rufi Volusiani viri clarissimi et inlustris ex praefecto praetorio et ex praefecto urbi et Caecinae Lollianae clarissimae et inlustris feminae deae Isidis sacerdotis filius iterato viginti annis expletis taurobolii sui aram constituit et consecravit X Kalendas Iunias domino nostro Valentiniano Augusto IIII et Neoterio conssulibus<br />
<br />
Publication: AE 1953, 00237 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Magnae Idaeae et Attidi Menotyranno Sextius Rusticus vir clarissimus et inlustris pater patrum dei Invicti Mithrae<br />
<br />
Publication: AE 1953, 00238 = AE 2000, +00136 Province: Roma Place: Roma<br />
<br />
:Diis Magnis Matri deum Idaeae et Attidi sancto Menotyranno Alfenius Ceionius Iulianus Kamenius vir clarissimus VII vir epulonum pater et hieroceryx sacrorum Soli Invicti Mithrae hierofanta Haecatae archibucolus dei liberi aram taurobolio criobolioque percepto dicabit! die XIIII Kalendas Augustas domino nostro Gratiano Augusto III et Equitio conssulibus<br />
<br />
Publication: CIL 06, 00499 p 3005, 3757 = CIL 06, 30779c = D 04147 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae Summae Parenti Hermae et Attidi Menotyranno Invicto Clodius Hermogenianus Caesarius vir clarissimus proconsul Africae praefectus urbis Romae XV vir sacris faciundis taurobolio criobolioque perfecto XIIII Kalendas Augustas diis animae suae mentisque custodibus aram dicavit domino nostro Gratiano Augusto tertium et 3 Aequitio conssulibus<br />
<br />
Publication: CIL 06, 00500 p 3005, 3757 = CIL 06, 30779d = D 04148 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno Conservatoribus suis Caelius Hilarianus vir clarissimus duodecimvir urbis Romae pater sacrorum et hieroceryx Invicti Mithrae sacerdos dei Liberi sacerdos deae Hecate domino nostro Gratiano Augusto et Merobaude conssulibus III Idus Maias<br />
<br />
Publication: CIL 06, 00501 p 3005, 3757 = CIL 06, 30779e = D 04149 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Sancto Menotyranno Quintus Clodius Flavianus vir clarissimus pontifex maior XVvir sacris faciundis septemvir epulonum pontifex dei Solis taurobolio criobolioque percepto aram dicavit Nonis Aprilibus FFllavis Merobaude II et Saturnino conssulibus<br />
<br />
Publication: CIL 06, 00508 p 3757 = D 04146 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Potentissimis Dis Matri deum Magnae et Attidi Menotyranno 3 Serapias honesta femina sacrata deum matris et Proserpinae taurobolium criobolium caernophorum perceptum per Flavium Antonium Eustochium sacerdotem Phryges maximus praesentibus et tradentibus cclarissimorum vvirorum ex amplissimo et sanctissimo collegio XV virum sacris faciundis die XIII Kalendas Maias cerealibus ddominis nnostris Constantino Maximo Augusto V et Licinio Iuniori Caesari conssulibus<br />
<br />
Publication: CIL 06, 00511 p 3005 = CLE 01529 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menoturano sacrum nobilis in causis forma celsusque Sabinus hic pater Invicti mystica victor habet sermo duos 3 reservans consimiles aufert et veneranda movet Cibeles Triodeia signa augentur meritis simbola tauroboli Rufius Caeionius Caeioni(?) Sabini filius(?) vir classimus pontifex maior hierofanta deae Hecatae augur publicus populi Romani Quiritium pater sacrorum Invicti Mthrae tauroboliatus Matris deum Magnae Idaeae et Attidis Minoturani et aram IIII Idus Martias Gratiano V et Merobaude consulibus dedicabit antiqua generose domo cui regia Vesta pontifici felix sacrato militat igne idem augur triplicis cultor venerande Dianae Persidicique Mithrae antistes Babloniae templi taurobolique simul magni dux mistice sacri<br />
<br />
Publication: CIL 06, 00512 p 3005, 3757 = CLE +00264 = D 04154 = SIRIS 00447 = RICIS-02, 005010212 = AE 2003, +00151 Province: Roma Place: Roma<br />
<br />
:Matri deum Magnae Idaeae et Attidi Menotyranno dis Magnis et Tutatoribus suis Ceionius Rufius Volusianus vir clarissimus et inlustris ex vicario Asiae et Ceioni Rufi Volusiani viri clarissimi et inlustris ex praefecto praetorio et ex praefecto urbi et Caecinae Lollianae clarissimae et inlustris feminae deae Isidis sacerdotis filius iterato viginti annis expletis taurobolii sui aram constituit et consecravit X Kalendas Iunias domino nostro Valentiniano Augusto IIII et Neoterio conssulibus</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3029User:Roger Pearse/JavaScript Basics2017-10-05T13:58:05Z<p>Roger Pearse: /* AngularJs / Angular */</p>
<hr />
<div>= Open command window on directory in windows explorer =<br />
<br />
Hold down shift and right-click folder, extra menu option.<br />
<br />
= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
A non-boolean value that counts as true is called "truthy," and a non-boolean value that counts as false is called "falsey." <br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
* [[File:Dojo_stuff.zip]]<br />
<br />
Here's a sample page:<br />
<br />
<pre><br />
<!DOCTYPE html><br />
<html ><br />
<head><br />
<br />
<style type="text/css"><br />
.example{<br />
margin: 8px;<br />
text-align: center;<br />
padding: 5px;<br />
border: 2px solid black;<br />
color: white;<br />
background-color: blue;<br />
width: 200px;<br />
height: 200px;<br />
}<br />
</style><br />
<br />
<!-- Specify async=true for modern/AMD mode, false for legacy mode --><br />
<!-- If we get "Uncaught ReferenceError: dojo is not defined" look at this<br />
https://stackoverflow.com/questions/14598719/dojo-tutorial-dojo-is-not-defined --><br />
<script>dojoConfig = {async: false, parseOnLoad: false}</script><br />
<br />
<!-- Include Dojo --><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.7/dojo/dojo.js"></script><br />
<br />
<script><br />
<br />
// dojo.ready(function(){<br />
// //alert("Dojo version " + dojo.version + " is loaded");<br />
// dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// });<br />
<br />
function init() {<br />
//alert("Dojo ready, version:" + dojo.version);<br />
//dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// More initialization here<br />
calc();<br />
}<br />
<br />
dojo.ready(init);<br />
<br />
function calc(){<br />
<br />
var node = dojo.byId("example");<br />
var marginsize = dojo._getMarginSize(node);<br />
var contentbox = dojo._getContentBox(node);<br />
var position = dojo.position(node);<br />
<br />
var height = dojo.style("example", "height");<br />
var padding = dojo.style("example", "padding");<br />
var margin = dojo.style("example", "margin");<br />
var border = dojo.style("example", "border");<br />
<br />
var info = ""<br />
+ "<br>css height = " + height<br />
+ "<br>css padding = " + padding<br />
+ "<br>css margin = " + margin<br />
+ "<br>css border = " + border<br />
+ "<br><br>node.scrollHeight = " + node.scrollHeight<br />
+ "<br>node.offsetHeight = " + node.offsetHeight<br />
+ "<br><br><table>"<br />
+ "<tr><td>contentbox.h = " + contentbox.h + " <td>" + " <td>" + JSON.stringify(contentbox)<br />
+ "<tr><td>position.h = " + position.h + " <td> Plus 2 lots of padding and border" + " <td>" + JSON.stringify(position)<br />
+ "<tr><td>marginsize.h = " + marginsize.h + " <td> Plus 2 lots of margin " + " <td>" + JSON.stringify(marginsize);<br />
<br />
dojo.byId("output").innerHTML = info; //JSON.stringify(output);<br />
}<br />
</script><br />
</head><br />
<body><br />
<br />
<!-- The box on the screen, styled and sized as above --><br />
<div class="example" id="example">Some example node 200px high</div><br />
<br />
<!-- The output --><br />
<p><strong>Output:</strong></p><br />
<br />
<!-- Just use pre ... but I can't for uploading to this wiki page --><br />
<div id="output" style="display: block;unicode-bidi: embed;font-family: monospace;white-space: pre;"></div><br />
<br />
</body><br />
</html><br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014. Source code is [https://github.com/DanWahlin/AngularIn20JavaScript here], but no good. My own project is here: [[File:NoddyAngularJs.zip]], edited with Visual Studio Code. Folder on desktop.<br />
* [https://docs.angularjs.org/misc/started Getting Started]<br />
* [https://docs.angularjs.org/guide/concepts AngularJS concepts]<br />
<br />
The principle behind Angular is to get away from DOM manipulation. Do UI stuff declaratively, and business logic with code.<br />
<br />
* [https://github.com/angular/angular-seed Angular seed project] - basic skeleton to get started</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:NoddyAngularJs.zip&diff=3028File:NoddyAngularJs.zip2017-10-05T12:00:29Z<p>Roger Pearse: Roger Pearse uploaded a new version of File:NoddyAngularJs.zip</p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3027User:Roger Pearse/JavaScript Basics2017-10-05T10:39:08Z<p>Roger Pearse: /* AngularJs / Angular */</p>
<hr />
<div>= Open command window on directory in windows explorer =<br />
<br />
Hold down shift and right-click folder, extra menu option.<br />
<br />
= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
A non-boolean value that counts as true is called "truthy," and a non-boolean value that counts as false is called "falsey." <br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
* [[File:Dojo_stuff.zip]]<br />
<br />
Here's a sample page:<br />
<br />
<pre><br />
<!DOCTYPE html><br />
<html ><br />
<head><br />
<br />
<style type="text/css"><br />
.example{<br />
margin: 8px;<br />
text-align: center;<br />
padding: 5px;<br />
border: 2px solid black;<br />
color: white;<br />
background-color: blue;<br />
width: 200px;<br />
height: 200px;<br />
}<br />
</style><br />
<br />
<!-- Specify async=true for modern/AMD mode, false for legacy mode --><br />
<!-- If we get "Uncaught ReferenceError: dojo is not defined" look at this<br />
https://stackoverflow.com/questions/14598719/dojo-tutorial-dojo-is-not-defined --><br />
<script>dojoConfig = {async: false, parseOnLoad: false}</script><br />
<br />
<!-- Include Dojo --><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.7/dojo/dojo.js"></script><br />
<br />
<script><br />
<br />
// dojo.ready(function(){<br />
// //alert("Dojo version " + dojo.version + " is loaded");<br />
// dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// });<br />
<br />
function init() {<br />
//alert("Dojo ready, version:" + dojo.version);<br />
//dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// More initialization here<br />
calc();<br />
}<br />
<br />
dojo.ready(init);<br />
<br />
function calc(){<br />
<br />
var node = dojo.byId("example");<br />
var marginsize = dojo._getMarginSize(node);<br />
var contentbox = dojo._getContentBox(node);<br />
var position = dojo.position(node);<br />
<br />
var height = dojo.style("example", "height");<br />
var padding = dojo.style("example", "padding");<br />
var margin = dojo.style("example", "margin");<br />
var border = dojo.style("example", "border");<br />
<br />
var info = ""<br />
+ "<br>css height = " + height<br />
+ "<br>css padding = " + padding<br />
+ "<br>css margin = " + margin<br />
+ "<br>css border = " + border<br />
+ "<br><br>node.scrollHeight = " + node.scrollHeight<br />
+ "<br>node.offsetHeight = " + node.offsetHeight<br />
+ "<br><br><table>"<br />
+ "<tr><td>contentbox.h = " + contentbox.h + " <td>" + " <td>" + JSON.stringify(contentbox)<br />
+ "<tr><td>position.h = " + position.h + " <td> Plus 2 lots of padding and border" + " <td>" + JSON.stringify(position)<br />
+ "<tr><td>marginsize.h = " + marginsize.h + " <td> Plus 2 lots of margin " + " <td>" + JSON.stringify(marginsize);<br />
<br />
dojo.byId("output").innerHTML = info; //JSON.stringify(output);<br />
}<br />
</script><br />
</head><br />
<body><br />
<br />
<!-- The box on the screen, styled and sized as above --><br />
<div class="example" id="example">Some example node 200px high</div><br />
<br />
<!-- The output --><br />
<p><strong>Output:</strong></p><br />
<br />
<!-- Just use pre ... but I can't for uploading to this wiki page --><br />
<div id="output" style="display: block;unicode-bidi: embed;font-family: monospace;white-space: pre;"></div><br />
<br />
</body><br />
</html><br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014. Source code is [https://github.com/DanWahlin/AngularIn20JavaScript here], but no good. My own project is here: [[File:NoddyAngularJs.zip]], edited with Visual Studio Code. Folder on desktop.<br />
* [https://docs.angularjs.org/misc/started Getting Started]<br />
* [https://docs.angularjs.org/guide/concepts AngularJS concepts]<br />
<br />
The principle behind Angular is to get away from DOM manipulation. Do UI stuff declaratively, and business logic with code.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3026User:Roger Pearse/JavaScript Basics2017-10-05T10:07:44Z<p>Roger Pearse: /* AngularJs / Angular */</p>
<hr />
<div>= Open command window on directory in windows explorer =<br />
<br />
Hold down shift and right-click folder, extra menu option.<br />
<br />
= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
A non-boolean value that counts as true is called "truthy," and a non-boolean value that counts as false is called "falsey." <br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
* [[File:Dojo_stuff.zip]]<br />
<br />
Here's a sample page:<br />
<br />
<pre><br />
<!DOCTYPE html><br />
<html ><br />
<head><br />
<br />
<style type="text/css"><br />
.example{<br />
margin: 8px;<br />
text-align: center;<br />
padding: 5px;<br />
border: 2px solid black;<br />
color: white;<br />
background-color: blue;<br />
width: 200px;<br />
height: 200px;<br />
}<br />
</style><br />
<br />
<!-- Specify async=true for modern/AMD mode, false for legacy mode --><br />
<!-- If we get "Uncaught ReferenceError: dojo is not defined" look at this<br />
https://stackoverflow.com/questions/14598719/dojo-tutorial-dojo-is-not-defined --><br />
<script>dojoConfig = {async: false, parseOnLoad: false}</script><br />
<br />
<!-- Include Dojo --><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.7/dojo/dojo.js"></script><br />
<br />
<script><br />
<br />
// dojo.ready(function(){<br />
// //alert("Dojo version " + dojo.version + " is loaded");<br />
// dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// });<br />
<br />
function init() {<br />
//alert("Dojo ready, version:" + dojo.version);<br />
//dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// More initialization here<br />
calc();<br />
}<br />
<br />
dojo.ready(init);<br />
<br />
function calc(){<br />
<br />
var node = dojo.byId("example");<br />
var marginsize = dojo._getMarginSize(node);<br />
var contentbox = dojo._getContentBox(node);<br />
var position = dojo.position(node);<br />
<br />
var height = dojo.style("example", "height");<br />
var padding = dojo.style("example", "padding");<br />
var margin = dojo.style("example", "margin");<br />
var border = dojo.style("example", "border");<br />
<br />
var info = ""<br />
+ "<br>css height = " + height<br />
+ "<br>css padding = " + padding<br />
+ "<br>css margin = " + margin<br />
+ "<br>css border = " + border<br />
+ "<br><br>node.scrollHeight = " + node.scrollHeight<br />
+ "<br>node.offsetHeight = " + node.offsetHeight<br />
+ "<br><br><table>"<br />
+ "<tr><td>contentbox.h = " + contentbox.h + " <td>" + " <td>" + JSON.stringify(contentbox)<br />
+ "<tr><td>position.h = " + position.h + " <td> Plus 2 lots of padding and border" + " <td>" + JSON.stringify(position)<br />
+ "<tr><td>marginsize.h = " + marginsize.h + " <td> Plus 2 lots of margin " + " <td>" + JSON.stringify(marginsize);<br />
<br />
dojo.byId("output").innerHTML = info; //JSON.stringify(output);<br />
}<br />
</script><br />
</head><br />
<body><br />
<br />
<!-- The box on the screen, styled and sized as above --><br />
<div class="example" id="example">Some example node 200px high</div><br />
<br />
<!-- The output --><br />
<p><strong>Output:</strong></p><br />
<br />
<!-- Just use pre ... but I can't for uploading to this wiki page --><br />
<div id="output" style="display: block;unicode-bidi: embed;font-family: monospace;white-space: pre;"></div><br />
<br />
</body><br />
</html><br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014. Source code is [https://github.com/DanWahlin/AngularIn20JavaScript here], but no good. My own project is here: [[File:NoddyAngularJs.zip]], edited with Visual Studio Code. Folder on desktop.<br />
* [https://docs.angularjs.org/misc/started Getting Started]<br />
* [https://docs.angularjs.org/guide/concepts AngularJS concepts]</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:NoddyAngularJs.zip&diff=3025File:NoddyAngularJs.zip2017-10-05T10:07:12Z<p>Roger Pearse: </p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3024User:Roger Pearse/JavaScript Basics2017-10-05T10:05:46Z<p>Roger Pearse: /* AngularJs / Angular */</p>
<hr />
<div>= Open command window on directory in windows explorer =<br />
<br />
Hold down shift and right-click folder, extra menu option.<br />
<br />
= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
A non-boolean value that counts as true is called "truthy," and a non-boolean value that counts as false is called "falsey." <br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
* [[File:Dojo_stuff.zip]]<br />
<br />
Here's a sample page:<br />
<br />
<pre><br />
<!DOCTYPE html><br />
<html ><br />
<head><br />
<br />
<style type="text/css"><br />
.example{<br />
margin: 8px;<br />
text-align: center;<br />
padding: 5px;<br />
border: 2px solid black;<br />
color: white;<br />
background-color: blue;<br />
width: 200px;<br />
height: 200px;<br />
}<br />
</style><br />
<br />
<!-- Specify async=true for modern/AMD mode, false for legacy mode --><br />
<!-- If we get "Uncaught ReferenceError: dojo is not defined" look at this<br />
https://stackoverflow.com/questions/14598719/dojo-tutorial-dojo-is-not-defined --><br />
<script>dojoConfig = {async: false, parseOnLoad: false}</script><br />
<br />
<!-- Include Dojo --><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.7/dojo/dojo.js"></script><br />
<br />
<script><br />
<br />
// dojo.ready(function(){<br />
// //alert("Dojo version " + dojo.version + " is loaded");<br />
// dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// });<br />
<br />
function init() {<br />
//alert("Dojo ready, version:" + dojo.version);<br />
//dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// More initialization here<br />
calc();<br />
}<br />
<br />
dojo.ready(init);<br />
<br />
function calc(){<br />
<br />
var node = dojo.byId("example");<br />
var marginsize = dojo._getMarginSize(node);<br />
var contentbox = dojo._getContentBox(node);<br />
var position = dojo.position(node);<br />
<br />
var height = dojo.style("example", "height");<br />
var padding = dojo.style("example", "padding");<br />
var margin = dojo.style("example", "margin");<br />
var border = dojo.style("example", "border");<br />
<br />
var info = ""<br />
+ "<br>css height = " + height<br />
+ "<br>css padding = " + padding<br />
+ "<br>css margin = " + margin<br />
+ "<br>css border = " + border<br />
+ "<br><br>node.scrollHeight = " + node.scrollHeight<br />
+ "<br>node.offsetHeight = " + node.offsetHeight<br />
+ "<br><br><table>"<br />
+ "<tr><td>contentbox.h = " + contentbox.h + " <td>" + " <td>" + JSON.stringify(contentbox)<br />
+ "<tr><td>position.h = " + position.h + " <td> Plus 2 lots of padding and border" + " <td>" + JSON.stringify(position)<br />
+ "<tr><td>marginsize.h = " + marginsize.h + " <td> Plus 2 lots of margin " + " <td>" + JSON.stringify(marginsize);<br />
<br />
dojo.byId("output").innerHTML = info; //JSON.stringify(output);<br />
}<br />
</script><br />
</head><br />
<body><br />
<br />
<!-- The box on the screen, styled and sized as above --><br />
<div class="example" id="example">Some example node 200px high</div><br />
<br />
<!-- The output --><br />
<p><strong>Output:</strong></p><br />
<br />
<!-- Just use pre ... but I can't for uploading to this wiki page --><br />
<div id="output" style="display: block;unicode-bidi: embed;font-family: monospace;white-space: pre;"></div><br />
<br />
</body><br />
</html><br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014. Source code is [https://github.com/DanWahlin/AngularIn20JavaScript here], but no good. My own project is here: <br />
* [https://docs.angularjs.org/misc/started Getting Started]<br />
* [https://docs.angularjs.org/guide/concepts AngularJS concepts]</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3023User:Roger Pearse/JavaScript Basics2017-10-05T09:31:50Z<p>Roger Pearse: /* Truthy and Falsy */</p>
<hr />
<div>= Open command window on directory in windows explorer =<br />
<br />
Hold down shift and right-click folder, extra menu option.<br />
<br />
= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
A non-boolean value that counts as true is called "truthy," and a non-boolean value that counts as false is called "falsey." <br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
* [[File:Dojo_stuff.zip]]<br />
<br />
Here's a sample page:<br />
<br />
<pre><br />
<!DOCTYPE html><br />
<html ><br />
<head><br />
<br />
<style type="text/css"><br />
.example{<br />
margin: 8px;<br />
text-align: center;<br />
padding: 5px;<br />
border: 2px solid black;<br />
color: white;<br />
background-color: blue;<br />
width: 200px;<br />
height: 200px;<br />
}<br />
</style><br />
<br />
<!-- Specify async=true for modern/AMD mode, false for legacy mode --><br />
<!-- If we get "Uncaught ReferenceError: dojo is not defined" look at this<br />
https://stackoverflow.com/questions/14598719/dojo-tutorial-dojo-is-not-defined --><br />
<script>dojoConfig = {async: false, parseOnLoad: false}</script><br />
<br />
<!-- Include Dojo --><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.7/dojo/dojo.js"></script><br />
<br />
<script><br />
<br />
// dojo.ready(function(){<br />
// //alert("Dojo version " + dojo.version + " is loaded");<br />
// dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// });<br />
<br />
function init() {<br />
//alert("Dojo ready, version:" + dojo.version);<br />
//dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// More initialization here<br />
calc();<br />
}<br />
<br />
dojo.ready(init);<br />
<br />
function calc(){<br />
<br />
var node = dojo.byId("example");<br />
var marginsize = dojo._getMarginSize(node);<br />
var contentbox = dojo._getContentBox(node);<br />
var position = dojo.position(node);<br />
<br />
var height = dojo.style("example", "height");<br />
var padding = dojo.style("example", "padding");<br />
var margin = dojo.style("example", "margin");<br />
var border = dojo.style("example", "border");<br />
<br />
var info = ""<br />
+ "<br>css height = " + height<br />
+ "<br>css padding = " + padding<br />
+ "<br>css margin = " + margin<br />
+ "<br>css border = " + border<br />
+ "<br><br>node.scrollHeight = " + node.scrollHeight<br />
+ "<br>node.offsetHeight = " + node.offsetHeight<br />
+ "<br><br><table>"<br />
+ "<tr><td>contentbox.h = " + contentbox.h + " <td>" + " <td>" + JSON.stringify(contentbox)<br />
+ "<tr><td>position.h = " + position.h + " <td> Plus 2 lots of padding and border" + " <td>" + JSON.stringify(position)<br />
+ "<tr><td>marginsize.h = " + marginsize.h + " <td> Plus 2 lots of margin " + " <td>" + JSON.stringify(marginsize);<br />
<br />
dojo.byId("output").innerHTML = info; //JSON.stringify(output);<br />
}<br />
</script><br />
</head><br />
<body><br />
<br />
<!-- The box on the screen, styled and sized as above --><br />
<div class="example" id="example">Some example node 200px high</div><br />
<br />
<!-- The output --><br />
<p><strong>Output:</strong></p><br />
<br />
<!-- Just use pre ... but I can't for uploading to this wiki page --><br />
<div id="output" style="display: block;unicode-bidi: embed;font-family: monospace;white-space: pre;"></div><br />
<br />
</body><br />
</html><br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014. Source code is [https://github.com/DanWahlin/AngularIn20JavaScript here].</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3022User:Roger Pearse/JavaScript Basics2017-10-05T08:01:32Z<p>Roger Pearse: </p>
<hr />
<div>= Open command window on directory in windows explorer =<br />
<br />
Hold down shift and right-click folder, extra menu option.<br />
<br />
= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
* [[File:Dojo_stuff.zip]]<br />
<br />
Here's a sample page:<br />
<br />
<pre><br />
<!DOCTYPE html><br />
<html ><br />
<head><br />
<br />
<style type="text/css"><br />
.example{<br />
margin: 8px;<br />
text-align: center;<br />
padding: 5px;<br />
border: 2px solid black;<br />
color: white;<br />
background-color: blue;<br />
width: 200px;<br />
height: 200px;<br />
}<br />
</style><br />
<br />
<!-- Specify async=true for modern/AMD mode, false for legacy mode --><br />
<!-- If we get "Uncaught ReferenceError: dojo is not defined" look at this<br />
https://stackoverflow.com/questions/14598719/dojo-tutorial-dojo-is-not-defined --><br />
<script>dojoConfig = {async: false, parseOnLoad: false}</script><br />
<br />
<!-- Include Dojo --><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.7/dojo/dojo.js"></script><br />
<br />
<script><br />
<br />
// dojo.ready(function(){<br />
// //alert("Dojo version " + dojo.version + " is loaded");<br />
// dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// });<br />
<br />
function init() {<br />
//alert("Dojo ready, version:" + dojo.version);<br />
//dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// More initialization here<br />
calc();<br />
}<br />
<br />
dojo.ready(init);<br />
<br />
function calc(){<br />
<br />
var node = dojo.byId("example");<br />
var marginsize = dojo._getMarginSize(node);<br />
var contentbox = dojo._getContentBox(node);<br />
var position = dojo.position(node);<br />
<br />
var height = dojo.style("example", "height");<br />
var padding = dojo.style("example", "padding");<br />
var margin = dojo.style("example", "margin");<br />
var border = dojo.style("example", "border");<br />
<br />
var info = ""<br />
+ "<br>css height = " + height<br />
+ "<br>css padding = " + padding<br />
+ "<br>css margin = " + margin<br />
+ "<br>css border = " + border<br />
+ "<br><br>node.scrollHeight = " + node.scrollHeight<br />
+ "<br>node.offsetHeight = " + node.offsetHeight<br />
+ "<br><br><table>"<br />
+ "<tr><td>contentbox.h = " + contentbox.h + " <td>" + " <td>" + JSON.stringify(contentbox)<br />
+ "<tr><td>position.h = " + position.h + " <td> Plus 2 lots of padding and border" + " <td>" + JSON.stringify(position)<br />
+ "<tr><td>marginsize.h = " + marginsize.h + " <td> Plus 2 lots of margin " + " <td>" + JSON.stringify(marginsize);<br />
<br />
dojo.byId("output").innerHTML = info; //JSON.stringify(output);<br />
}<br />
</script><br />
</head><br />
<body><br />
<br />
<!-- The box on the screen, styled and sized as above --><br />
<div class="example" id="example">Some example node 200px high</div><br />
<br />
<!-- The output --><br />
<p><strong>Output:</strong></p><br />
<br />
<!-- Just use pre ... but I can't for uploading to this wiki page --><br />
<div id="output" style="display: block;unicode-bidi: embed;font-family: monospace;white-space: pre;"></div><br />
<br />
</body><br />
</html><br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014. Source code is [https://github.com/DanWahlin/AngularIn20JavaScript here].</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3021User:Roger Pearse/JavaScript Basics2017-10-05T07:58:40Z<p>Roger Pearse: /* AngularJs / Angular */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
* [[File:Dojo_stuff.zip]]<br />
<br />
Here's a sample page:<br />
<br />
<pre><br />
<!DOCTYPE html><br />
<html ><br />
<head><br />
<br />
<style type="text/css"><br />
.example{<br />
margin: 8px;<br />
text-align: center;<br />
padding: 5px;<br />
border: 2px solid black;<br />
color: white;<br />
background-color: blue;<br />
width: 200px;<br />
height: 200px;<br />
}<br />
</style><br />
<br />
<!-- Specify async=true for modern/AMD mode, false for legacy mode --><br />
<!-- If we get "Uncaught ReferenceError: dojo is not defined" look at this<br />
https://stackoverflow.com/questions/14598719/dojo-tutorial-dojo-is-not-defined --><br />
<script>dojoConfig = {async: false, parseOnLoad: false}</script><br />
<br />
<!-- Include Dojo --><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.7/dojo/dojo.js"></script><br />
<br />
<script><br />
<br />
// dojo.ready(function(){<br />
// //alert("Dojo version " + dojo.version + " is loaded");<br />
// dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// });<br />
<br />
function init() {<br />
//alert("Dojo ready, version:" + dojo.version);<br />
//dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// More initialization here<br />
calc();<br />
}<br />
<br />
dojo.ready(init);<br />
<br />
function calc(){<br />
<br />
var node = dojo.byId("example");<br />
var marginsize = dojo._getMarginSize(node);<br />
var contentbox = dojo._getContentBox(node);<br />
var position = dojo.position(node);<br />
<br />
var height = dojo.style("example", "height");<br />
var padding = dojo.style("example", "padding");<br />
var margin = dojo.style("example", "margin");<br />
var border = dojo.style("example", "border");<br />
<br />
var info = ""<br />
+ "<br>css height = " + height<br />
+ "<br>css padding = " + padding<br />
+ "<br>css margin = " + margin<br />
+ "<br>css border = " + border<br />
+ "<br><br>node.scrollHeight = " + node.scrollHeight<br />
+ "<br>node.offsetHeight = " + node.offsetHeight<br />
+ "<br><br><table>"<br />
+ "<tr><td>contentbox.h = " + contentbox.h + " <td>" + " <td>" + JSON.stringify(contentbox)<br />
+ "<tr><td>position.h = " + position.h + " <td> Plus 2 lots of padding and border" + " <td>" + JSON.stringify(position)<br />
+ "<tr><td>marginsize.h = " + marginsize.h + " <td> Plus 2 lots of margin " + " <td>" + JSON.stringify(marginsize);<br />
<br />
dojo.byId("output").innerHTML = info; //JSON.stringify(output);<br />
}<br />
</script><br />
</head><br />
<body><br />
<br />
<!-- The box on the screen, styled and sized as above --><br />
<div class="example" id="example">Some example node 200px high</div><br />
<br />
<!-- The output --><br />
<p><strong>Output:</strong></p><br />
<br />
<!-- Just use pre ... but I can't for uploading to this wiki page --><br />
<div id="output" style="display: block;unicode-bidi: embed;font-family: monospace;white-space: pre;"></div><br />
<br />
</body><br />
</html><br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014. Source code is [https://github.com/DanWahlin/AngularIn20JavaScript here].</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:Dojo_stuff.zip&diff=3020File:Dojo stuff.zip2017-09-14T14:35:36Z<p>Roger Pearse: Roger Pearse uploaded a new version of File:Dojo stuff.zip</p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:Dojo_stuff.zip&diff=3019File:Dojo stuff.zip2017-09-14T13:03:07Z<p>Roger Pearse: Roger Pearse uploaded a new version of File:Dojo stuff.zip</p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3018User:Roger Pearse/JavaScript Basics2017-09-14T10:45:26Z<p>Roger Pearse: /* Dojo */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
* [[File:Dojo_stuff.zip]]<br />
<br />
Here's a sample page:<br />
<br />
<pre><br />
<!DOCTYPE html><br />
<html ><br />
<head><br />
<br />
<style type="text/css"><br />
.example{<br />
margin: 8px;<br />
text-align: center;<br />
padding: 5px;<br />
border: 2px solid black;<br />
color: white;<br />
background-color: blue;<br />
width: 200px;<br />
height: 200px;<br />
}<br />
</style><br />
<br />
<!-- Specify async=true for modern/AMD mode, false for legacy mode --><br />
<!-- If we get "Uncaught ReferenceError: dojo is not defined" look at this<br />
https://stackoverflow.com/questions/14598719/dojo-tutorial-dojo-is-not-defined --><br />
<script>dojoConfig = {async: false, parseOnLoad: false}</script><br />
<br />
<!-- Include Dojo --><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.7/dojo/dojo.js"></script><br />
<br />
<script><br />
<br />
// dojo.ready(function(){<br />
// //alert("Dojo version " + dojo.version + " is loaded");<br />
// dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// });<br />
<br />
function init() {<br />
//alert("Dojo ready, version:" + dojo.version);<br />
//dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// More initialization here<br />
calc();<br />
}<br />
<br />
dojo.ready(init);<br />
<br />
function calc(){<br />
<br />
var node = dojo.byId("example");<br />
var marginsize = dojo._getMarginSize(node);<br />
var contentbox = dojo._getContentBox(node);<br />
var position = dojo.position(node);<br />
<br />
var height = dojo.style("example", "height");<br />
var padding = dojo.style("example", "padding");<br />
var margin = dojo.style("example", "margin");<br />
var border = dojo.style("example", "border");<br />
<br />
var info = ""<br />
+ "<br>css height = " + height<br />
+ "<br>css padding = " + padding<br />
+ "<br>css margin = " + margin<br />
+ "<br>css border = " + border<br />
+ "<br><br>node.scrollHeight = " + node.scrollHeight<br />
+ "<br>node.offsetHeight = " + node.offsetHeight<br />
+ "<br><br><table>"<br />
+ "<tr><td>contentbox.h = " + contentbox.h + " <td>" + " <td>" + JSON.stringify(contentbox)<br />
+ "<tr><td>position.h = " + position.h + " <td> Plus 2 lots of padding and border" + " <td>" + JSON.stringify(position)<br />
+ "<tr><td>marginsize.h = " + marginsize.h + " <td> Plus 2 lots of margin " + " <td>" + JSON.stringify(marginsize);<br />
<br />
dojo.byId("output").innerHTML = info; //JSON.stringify(output);<br />
}<br />
</script><br />
</head><br />
<body><br />
<br />
<!-- The box on the screen, styled and sized as above --><br />
<div class="example" id="example">Some example node 200px high</div><br />
<br />
<!-- The output --><br />
<p><strong>Output:</strong></p><br />
<br />
<!-- Just use pre ... but I can't for uploading to this wiki page --><br />
<div id="output" style="display: block;unicode-bidi: embed;font-family: monospace;white-space: pre;"></div><br />
<br />
</body><br />
</html><br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:Dojo_stuff.zip&diff=3017File:Dojo stuff.zip2017-09-14T10:44:54Z<p>Roger Pearse: </p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3016User:Roger Pearse/JavaScript Basics2017-09-13T08:16:40Z<p>Roger Pearse: /* Dojo */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
Here's a sample page:<br />
<br />
<pre><br />
<!DOCTYPE html><br />
<html ><br />
<head><br />
<br />
<style type="text/css"><br />
.example{<br />
margin: 8px;<br />
text-align: center;<br />
padding: 5px;<br />
border: 2px solid black;<br />
color: white;<br />
background-color: blue;<br />
width: 200px;<br />
height: 200px;<br />
}<br />
</style><br />
<br />
<!-- Specify async=true for modern/AMD mode, false for legacy mode --><br />
<!-- If we get "Uncaught ReferenceError: dojo is not defined" look at this<br />
https://stackoverflow.com/questions/14598719/dojo-tutorial-dojo-is-not-defined --><br />
<script>dojoConfig = {async: false, parseOnLoad: false}</script><br />
<br />
<!-- Include Dojo --><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.7/dojo/dojo.js"></script><br />
<br />
<script><br />
<br />
// dojo.ready(function(){<br />
// //alert("Dojo version " + dojo.version + " is loaded");<br />
// dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// });<br />
<br />
function init() {<br />
//alert("Dojo ready, version:" + dojo.version);<br />
//dojo.byId("greeting").innerHTML += ", from " + dojo.version;<br />
// More initialization here<br />
calc();<br />
}<br />
<br />
dojo.ready(init);<br />
<br />
function calc(){<br />
<br />
var node = dojo.byId("example");<br />
var marginsize = dojo._getMarginSize(node);<br />
var contentbox = dojo._getContentBox(node);<br />
var position = dojo.position(node);<br />
<br />
var height = dojo.style("example", "height");<br />
var padding = dojo.style("example", "padding");<br />
var margin = dojo.style("example", "margin");<br />
var border = dojo.style("example", "border");<br />
<br />
var info = ""<br />
+ "<br>css height = " + height<br />
+ "<br>css padding = " + padding<br />
+ "<br>css margin = " + margin<br />
+ "<br>css border = " + border<br />
+ "<br><br>node.scrollHeight = " + node.scrollHeight<br />
+ "<br>node.offsetHeight = " + node.offsetHeight<br />
+ "<br><br><table>"<br />
+ "<tr><td>contentbox.h = " + contentbox.h + " <td>" + " <td>" + JSON.stringify(contentbox)<br />
+ "<tr><td>position.h = " + position.h + " <td> Plus 2 lots of padding and border" + " <td>" + JSON.stringify(position)<br />
+ "<tr><td>marginsize.h = " + marginsize.h + " <td> Plus 2 lots of margin " + " <td>" + JSON.stringify(marginsize);<br />
<br />
dojo.byId("output").innerHTML = info; //JSON.stringify(output);<br />
}<br />
</script><br />
</head><br />
<body><br />
<br />
<!-- The box on the screen, styled and sized as above --><br />
<div class="example" id="example">Some example node 200px high</div><br />
<br />
<!-- The output --><br />
<p><strong>Output:</strong></p><br />
<br />
<!-- Just use pre ... but I can't for uploading to this wiki page --><br />
<div id="output" style="display: block;unicode-bidi: embed;font-family: monospace;white-space: pre;"></div><br />
<br />
</body><br />
</html><br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3015User:Roger Pearse/JavaScript Basics2017-09-13T08:12:29Z<p>Roger Pearse: /* AngularJs / Angular */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= Dojo =<br />
<br />
You can carry on working with legacy Dojo so long as you specify async false.<br />
<br />
Here's a sample page:<br />
<br />
<br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3014User:Roger Pearse/JavaScript Basics2017-08-25T14:09:25Z<p>Roger Pearse: /* AngularJs / Angular */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
* AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
* Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
* Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3013User:Roger Pearse/JavaScript Basics2017-08-25T14:09:04Z<p>Roger Pearse: </p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre><br />
<br />
= AngularJs / Angular =<br />
<br />
AngularJS is version 1. [http://Angularjs.org Website for v1]<br />
Angular = Angular 2, a rewrite and different thing. [https://angular.io/ Website for v2]<br />
Angular 4 is an update of Angular 2.<br />
<br />
https://www.youtube.com/watch?v=tnXO-i7944M - YouTube. Dan Wahlin - AngularJS in 20ish Minutes - NG-Conf 2014.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3012User:Roger Pearse/JavaScript Basics2017-07-24T14:16:47Z<p>Roger Pearse: /* Chrome tips */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
[[File:Devtools-source-javascript.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:Devtools-source-javascript.png&diff=3011File:Devtools-source-javascript.png2017-07-24T14:16:30Z<p>Roger Pearse: </p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3010User:Roger Pearse/JavaScript Basics2017-07-24T14:16:05Z<p>Roger Pearse: /* Chrome tips */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
To find the JavaScript source, in order to set breakpoints, open the "other domain" and go down through files in order.<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3009User:Roger Pearse/JavaScript Basics2017-07-13T14:02:14Z<p>Roger Pearse: /* Closures */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
[[File:Object-prototype-empty.png]]<br />
<br />
That [[Prototype]] has a “magical” meaning. When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, such thing is called “prototypal inheritance”. <br />
<br />
The property [[Prototype]] is internal and hidden, but there are many ways to set it. One of them is to use __proto__, like this:<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal;<br />
</pre><br />
<br />
If we look for a property in rabbit, and it’s missing, JavaScript automatically takes it from animal.<br />
<br />
<pre><br />
let animal = {<br />
eats: true<br />
};<br />
let rabbit = {<br />
jumps: true<br />
};<br />
<br />
rabbit.__proto__ = animal; // (*)<br />
<br />
// we can find both properties in rabbit now:<br />
alert( rabbit.eats ); // true (**)<br />
alert( rabbit.jumps ); // true<br />
</pre><br />
<br />
Here the line (*) sets animal to be a prototype of rabbit.<br />
<br />
Then, when alert tries to read property rabbit.eats (**), it’s not in rabbit, so JavaScript follows the [[Prototype]] reference and finds it in animal (look from the bottom up):<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:Object-prototype-empty.png&diff=3008File:Object-prototype-empty.png2017-07-13T14:00:07Z<p>Roger Pearse: </p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3007User:Roger Pearse/JavaScript Basics2017-07-13T13:59:49Z<p>Roger Pearse: /* Closures */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
=== Prototypal Inheritance ===<br />
<br />
This involves reuse without defining classes.<br />
<br />
* https://javascript.info/prototype-inheritance<br />
<br />
In JavaScript, objects have a special hidden property [[Prototype]]. This is null by default, but can be set to point to another object. That object is called “a prototype”.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3006User:Roger Pearse/JavaScript Basics2017-07-13T13:42:18Z<p>Roger Pearse: /* Closures */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
Beware - long lived closures can cause memory consumption.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3005User:Roger Pearse/JavaScript Basics2017-07-13T13:35:56Z<p>Roger Pearse: /* Closures */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''Name two uses for closures'''.<br />
<br />
* Factory functions - create numbers of related functions.<br />
* Namespacing private functions - keeping them limited in scope.<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3004User:Roger Pearse/JavaScript Basics2017-07-13T13:23:24Z<p>Roger Pearse: /* Closures */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''What is a Closure?''' - a stateful function<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3003User:Roger Pearse/JavaScript Basics2017-07-13T13:22:14Z<p>Roger Pearse: /* Closures */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
'''What is a Closure?'''<br />
<br />
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.<br />
<br />
To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function.<br />
<br />
The inner function will have access to the variables in the outer function scope, even after the outer function has returned.<br />
<br />
'''Using Closures (Examples)'''<br />
<br />
Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods.<br />
<br />
* https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3002User:Roger Pearse/JavaScript Basics2017-07-13T13:15:14Z<p>Roger Pearse: /* Callbacks, synchronous and asynchronous */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
=== Closures ===<br />
<br />
* https://www.w3schools.com/js/js_function_closures.asp<br />
<br />
<pre><br />
var greetingFactory = function(greeting) { // <-- self-invoking function; runs only once<br />
<br />
// Set any private variables - once<br />
<br />
return function(person) { // <-- the function expression<br />
return greeting + “ “ + person;<br />
};<br />
};<br />
<br />
// Run the self-invoking function, and return the function expression inner-function<br />
var closure = greetingFactory(“Hi”);<br />
<br />
// run the inner function<br />
closure(“Louis”); // Hi Louis<br />
</pre><br />
<br />
* The variable ''greetingFactory'' is assigned the return value of a self-invoking function.<br />
<br />
* The self-invoking function only runs once. It sets any variables, and returns a function expression.<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=3001User:Roger Pearse/JavaScript Basics2017-07-13T12:58:10Z<p>Roger Pearse: </p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
Further reading:<br />
* You Don’t Know JavaScript series<br />
* Scotch.io tutorials<br />
* Codecademy tutorials<br />
* JavaScript weekly newsletter<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:NoddyCallbacks.zip&diff=3000File:NoddyCallbacks.zip2017-07-13T11:22:51Z<p>Roger Pearse: Roger Pearse uploaded a new version of File:NoddyCallbacks.zip</p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2999User:Roger Pearse/JavaScript Basics2017-07-13T11:22:08Z<p>Roger Pearse: /* Callbacks, synchronous and asynchronous */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
it('Doms test', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
// Define a function and assign to a variable "callbackExample", which takes another function and executes it after a delay<br />
// Set the delay to 5 seconds<br />
var callbackExample = function(callback) {<br />
setTimeout(callback, 5000);<br />
};<br />
<br />
// Call the function "callbackExample", passing in an anonymous function that writes "done"<br />
// This will be executed after 5 seconds.<br />
callbackExample(function() {<br />
console.log("done by Dom");<br />
done(); // added by me at the end of the long-running bit<br />
});<br />
<br />
});<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2998User:Roger Pearse/JavaScript Basics2017-07-13T11:18:46Z<p>Roger Pearse: /* JavaScript Language */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
<br />
})<br />
</pre><br />
<br />
* [[File:NoddyCallbacks.zip]] - sample project<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:NoddyCallbacks.zip&diff=2997File:NoddyCallbacks.zip2017-07-13T11:18:19Z<p>Roger Pearse: </p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2996User:Roger Pearse/JavaScript Basics2017-07-13T11:17:54Z<p>Roger Pearse: /* JavaScript Language */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
=== Callbacks, synchronous and asynchronous ===<br />
<br />
A mocha test:<br />
<br />
<pre><br />
/**<br />
* A series of tests to demonstrate async callbacks and potential problems in node.js and mocha<br />
* <br />
* To Run: <br />
* cd test<br />
* mocha callbackTest.js<br />
*/<br />
var assert = require('assert');<br />
<br />
// Test suite<br />
describe('Testing Callbacks', function(){<br />
<br />
//--------------------------------------------------------<br />
<br />
// test<br />
it('Synchronous callback', function(){<br />
<br />
// A function<br />
function greeting(name) {<br />
console.log('Hello ' + name);<br />
}<br />
<br />
// A function that takes a function as a parameter<br />
function processUserInput(callback) {<br />
var name = "fred";<br />
callback(name);<br />
}<br />
<br />
// Run the second function, passing in the first<br />
processUserInput(greeting);<br />
});<br />
//--------------------------------------------------------<br />
<br />
// test - but this does not work... the timeout is cancelled by the end of the test,<br />
// so the second and third never run. It works fine in browser tho<br />
// https://houssein.me/javascript/2016/05/10/asynchronous-javascript-callbacks.html<br />
it('Asynchronous callback which fails', function(){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
}, 3000);<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - use done() with mocha.<br />
// https://medium.com/caffeine-and-testing/async-testing-with-mocha-with-callbacks-and-promises-5d0002661b3f<br />
// However if timeout is greater than 2000, it fails. <br />
// " Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves."<br />
it('Asynchronous callback with done', function(done){<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 1500);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
//--------------------------------------------------------<br />
<br />
// Here's how to fix the previous test - specify a timeout for mocha.<br />
// Discussion of this:<br />
// https://stackoverflow.com/questions/16607039/in-mocha-testing-while-calling-asynchronous-function-how-to-avoid-the-timeout-er<br />
// You can either set the timeout when running your test:<br />
// mocha --timeout 15000<br />
// Or you can set the timeout for each suite or each test programmatically:<br />
// this.timeout(15000); // add under the describe() or the it()<br />
it('Asynchronous callback with done and timeout', function(done){<br />
<br />
this.timeout(15000); // add under the describe() or the it()<br />
<br />
function functionFirst(callback) {<br />
setTimeout(function() {<br />
console.log('Second action');<br />
callback();<br />
// Mocha tool to wait until done<br />
done(); // <--- This was the bit I added to wait<br />
}, 3000);<br />
<br />
}<br />
<br />
function functionSecond() {<br />
console.log('Third action');<br />
}<br />
<br />
functionFirst(function(){<br />
functionSecond();<br />
});<br />
<br />
console.log('First action');<br />
<br />
});<br />
<br />
<br />
})<br />
</pre><br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2995User:Roger Pearse/JavaScript Basics2017-07-13T09:46:44Z<p>Roger Pearse: /* JavaScript Language */</p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
=== Truthy and Falsy ===<br />
<br />
* http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html<br />
<br />
When we say that a value is "truthy" in JavaScript, we don't just mean that the value is true. Rather, what we mean is that the value coerces to true when evaluated in a boolean context. <br />
<br />
Used for conciseness, to avoid saying "if (x === undefined)".<br />
<br />
Most things are truthy; only six are falsey: false, null, undefined, NaN, 0, "". All the rest expressions are truthy. (Total crap concept)<br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2994User:Roger Pearse/JavaScript Basics2017-07-11T09:09:40Z<p>Roger Pearse: </p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload". (This menu only appears when developer tools are open)<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2993User:Roger Pearse/JavaScript Basics2017-07-11T09:02:27Z<p>Roger Pearse: </p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload"<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.<br />
<br />
= Local http server =<br />
<br />
* https://www.npmjs.com/package/http-server<br />
<br />
Installation via npm:<br />
<pre><br />
npm install http-server -g<br />
</pre><br />
<br />
This will install http-server globally so that it may be run from the command line.<br />
<br />
<pre><br />
Usage:<br />
http-server [path] [options]<br />
</pre><br />
<br />
[path] defaults to ./public if the folder exists, and ./ otherwise.<br />
<br />
Now you can visit http://localhost:8080 to view your server. Then browse to files.<br />
<br />
<pre><br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ npm install http-server -g<br />
<br />
C:\Users\rpearse\AppData\Roaming\npm\http-server -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
C:\Users\rpearse\AppData\Roaming\npm\hs -> C:\Users\rpearse\AppData\Roaming\npm\node_modules\http-server\bin\http-server<br />
+ http-server@0.10.0<br />
added 23 packages in 4.201s<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$<br />
<br />
rpearse@MKNB740 MINGW64 /u/NoddyDojo16<br />
$ http-server<br />
Starting up http-server, serving ./<br />
Available on:<br />
http://172.19.37.72:8080<br />
http://127.0.0.1:8080<br />
Hit CTRL-C to stop the server<br />
[Tue Jul 11 2017 10:00:15 GMT+0100 (GMT Summer Time)] "GET /" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
[Tue Jul 11 2017 10:00:16 GMT+0100 (GMT Summer Time)] "GET /favicon.ico" Error (404): "Not found"<br />
[Tue Jul 11 2017 10:00:18 GMT+0100 (GMT Summer Time)] "GET /helloDojo.htm" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko"<br />
</pre></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2992User:Roger Pearse/JavaScript Basics2017-07-11T08:33:23Z<p>Roger Pearse: </p>
<hr />
<div>= Load without saying http =<br />
<br />
If you omit http, then the script will load correctly whether http or https. Otherwise it may give errors.<br />
<br />
<pre><br />
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.6.3/dojo/dojo.xd.js"></script><br />
</pre><br />
<br />
= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload"<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:Chrome-right-click-on-refresh.png&diff=2991File:Chrome-right-click-on-refresh.png2017-07-10T15:34:28Z<p>Roger Pearse: Roger Pearse uploaded a new version of File:Chrome-right-click-on-refresh.png</p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:Chrome-right-click-on-refresh.png&diff=2990File:Chrome-right-click-on-refresh.png2017-07-10T15:31:07Z<p>Roger Pearse: Roger Pearse uploaded a new version of File:Chrome-right-click-on-refresh.png</p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2989User:Roger Pearse/JavaScript Basics2017-07-10T15:15:05Z<p>Roger Pearse: </p>
<hr />
<div>= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload"<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
[[File:Chrome-inspect-hover.png]]<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:Chrome-inspect-hover.png&diff=2988File:Chrome-inspect-hover.png2017-07-10T15:14:37Z<p>Roger Pearse: </p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2987User:Roger Pearse/JavaScript Basics2017-07-10T15:14:16Z<p>Roger Pearse: </p>
<hr />
<div>= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload"<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2986User:Roger Pearse/JavaScript Basics2017-07-10T15:13:54Z<p>Roger Pearse: </p>
<hr />
<div>= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload"<br />
<br />
[[File:Chrome-right-click-on-refresh.png]]<br />
<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.</div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=File:Chrome-right-click-on-refresh.png&diff=2985File:Chrome-right-click-on-refresh.png2017-07-10T15:13:32Z<p>Roger Pearse: </p>
<hr />
<div></div>Roger Pearsehttps://roger-pearse.com/wiki/index.php?title=User:Roger_Pearse/JavaScript_Basics&diff=2984User:Roger Pearse/JavaScript Basics2017-07-10T15:13:12Z<p>Roger Pearse: </p>
<hr />
<div>= Chrome tips =<br />
<br />
Right-click on the reload, you get the menu - choose "empty cache and hard reload"<br />
<br />
<br />
To inspect by hovering, click the left hand box+arrow. The elements tab will move to the item. The Network tab is worth having open on load, because it will list the .js files being loaded.<br />
<br />
<br />
<br />
= JavaScript Language =<br />
<br />
* [https://webapplog.com/es6/ Top 10 ES6 Features Every Busy JavaScript Developer Must Know] - ES6 = JavaScript 2015<br />
* [https://en.m.wikipedia.org/wiki/TypeScript TypeScript] - Typed JavaScript with a "transpiler" (or translator)<br />
* [https://javascript.info/ Modern JavaScript Tutorial] - looks very sound<br />
<br />
=== Single line functions using arrow operator ===<br />
<br />
* https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/<br />
<br />
====Example====<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', () => alert(1));<br />
<br />
});<br />
</pre><br />
<br />
is equivalent to:<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
it('test 1', function() {<br />
alert(1);<br />
});<br />
<br />
});<br />
</pre><br />
<br />
====More info====<br />
<br />
There’s one more syntax for creating functions – very simple and concise. It’s called “arrow functions”, because it looks like this:<br />
<br />
<pre><br />
let func = (arg1, arg2, ...argN) => expression<br />
</pre><br />
<br />
This creates a function ''func'' that has arguments ''arg1..argN'', evaluates the expression on the right side with their use and returns its result.<br />
<br />
In other words, it’s roughly the same as:<br />
<br />
<pre><br />
let func = function(arg1, arg2, ...argN) {<br />
return expression;<br />
}<br />
</pre><br />
<br />
But much shorter. Example:<br />
<br />
Normal function:<br />
<br />
<pre><br />
let sum = function(a, b) {<br />
return a + b;<br />
};<br />
</pre><br />
<br />
Arrow function:<br />
<br />
<pre><br />
let sum = (a, b) => a + b;<br />
<br />
alert( sum(1, 2) ); // 3<br />
</pre><br />
<br />
If we have only one argument, then parentheses can be omitted, making that even shorter:<br />
<br />
<pre><br />
// same as<br />
// let double = function(n) { return n*2 }<br />
let double = n => n*2;<br />
<br />
alert( double(3) ); // 6<br />
</pre><br />
<br />
If there are no arguments, we can put empty parentheses:<br />
<br />
<pre><br />
let sayHi = () => alert("Hello!");<br />
<br />
sayHi();<br />
</pre><br />
<br />
= Installing stuff with NPM = <br />
<br />
Download and install nodejs. That gives you npm. This will end up in c:\program files.<br />
<br />
Then you can install tools globally, or inside the project. Things like npm are global; things like Jasmine and Mocha are put inside the project.<br />
<br />
== Install into the project == <br />
<br />
Install tools into the project using:<br />
<br />
<pre><br />
npm install karma --save-dev<br />
</pre><br />
<br />
Rather than globally with <br />
<br />
<pre><br />
npm install karma -g <br />
</pre><br />
<br />
because then you aren’t dependent on local PC configuration. It's part of the project, in other words.<br />
<br />
What’s –save-dev? That’s an option that inserts an entry pointing to the installed packages in the ‘devDependencies’ section of the ''package.json'' file. It signifies that a developer will need this package to work with the application, but it’s not required to run the application i.e. in production. So this is test-only stuff.<br />
<br />
http://www.bradoncode.com/blog/2015/05/19/karma-angularjs-testing/<br />
<br />
== Starting a new node project ==<br />
<br />
Start any node.js project by:<br />
<br />
<pre><br />
mkdir MyProject<br />
cd MyProject<br />
echo {} >> package.json<br />
</pre><br />
<br />
== Starting the project 2 ==<br />
<br />
Npm's init command line option will launch a wizard, which creates a package.json for our project.<br />
<br />
<pre><br />
npm init<br />
</pre><br />
<br />
Do this after creating the directory.<br />
<br />
== Path problem in Windows ==<br />
<br />
If you find that stuff installed with npm is not in the path in git bash, this means that when node was installed, the idiot didn't install as administrator, and the path stuff ended up in his local environment variables, rather than in the system environment variables. Might be able to fix via Windows | env, manually. Otherwise deinstall node from Control Panel, and reinstall.<br />
<br />
= Editor = <br />
<br />
== Getting started with VS Code ==<br />
<br />
* Get it from here: https://code.visualstudio.com/Download<br />
* [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial Great little tutorial! – add to basics] - VS Code is the editor to use.<br />
* [http://blog.wolksoftware.com/setting-up-your-typescript-vs-code-development-environment Setting up a VS Code for typescript, mocha, etc] - good on VS Code extensions<br />
<br />
Dark IDE seems to be a point of pride for JavaScript IDE's - you're not a professional unless you are using that.<br />
<br />
Comparison of IDE's (googled for ''node js ide'') - useful! https://www.slant.co/topics/46/~best-ides-for-node-js<br />
<br />
Webstorm is in first place, but VS Code is next, and free.<br />
<br />
NOTE: "clear" works in the IDE<br />
<br />
== Coverage in editor ==<br />
<br />
Webstorm includes code coverage in IDE, whereas VS Code has to use the paid for [https://wallabyjs.com/ Wallaby].<br />
<br />
* https://blogs.oracle.com/geertjan/karma-istanbul-code-coverage-in-netbeans-ide<br />
<br />
* [https://medium.com/@Zyklus/beautiful-seamless-javascript-testing-in-10-minutes-2a743637035b Wallaby setup]<br />
<br />
= Node.js =<br />
<br />
NodeJs is a way to run JavaScript to create server-side json-based webservices very lightly. The MEAN stack - NodeJs and Mongo - is intended to replace the LAMP stack with PHP and Postgres, and scales and runs far faster.<br />
<br />
It embeds the Google "V8" JavaScript Engine, which is open source.<br />
<br />
* [https://www.w3schools.com/nodejs/nodejs_get_started.asp W3 Schools tutorial]<br />
<br />
* [https://venturebeat.com/2012/01/07/building-consumer-apps-with-node/ Why use Node.js – to replace php and postgres, use node.js and mongo. More scalable.]<br />
<br />
== Noddy example ==<br />
<br />
My first js (saved in ''myfirst.js''):<br />
<br />
<pre><br />
'use strict'<br />
<br />
// Based on:<br />
// https://www.w3schools.com/nodejs/nodejs_get_started.asp<br />
// Revised against:<br />
// https://nodejs.org/api/synopsis.html<br />
<br />
// Get a handle on the http interfaces in node.js<br />
// originally had "var" - use const (for immutable) or let (for assignable)<br />
const http = require('http');<br />
<br />
const hostname = '127.0.0.1';<br />
const port = 8080;<br />
<br />
// Create a server and pass a function in to listen to the request.<br />
// The function passed in is a "request listener" which is automatically added to the "request" event<br />
// The createServer() returns a new instance of http.Server<br />
// In the horrible condensed way of js, the server is activated at the same time by .listen() on the end,<br />
// in the original example. But split out in the node.js docs, so have done the same<br />
const myServer = http.createServer(function (request, response) {<br />
response.writeHead(200, {'Content-Type': 'text/html'});<br />
response.end('Hello World!');<br />
});<br />
<br />
myServer.listen(port, hostname); <br />
<br />
console.log("Not blocked by the listen");<br />
</pre><br />
<br />
[[File:NoddyJs.zip]]<br />
<br />
Create a file, then in git bash (or in the VS code terminal) do<br />
<pre><br />
node myfirst.js<br />
</pre><br />
<br />
Then open Chrome and do http://localhost:8080, and see the hello world.<br />
<br />
== Modules available for nodejs ==<br />
<br />
The above example uses the http module. Here's a list of all of them in node 6: https://www.w3schools.com/nodejs/ref_modules.asp<br />
<br />
== Colours in console ==<br />
<br />
* https://dev.to/moriczgergo/nodejs-console-colors-101<br />
<br />
<pre><br />
npm install chalk<br />
</pre><br />
<br />
and<br />
<br />
<pre><br />
const chalk = require('chalk');<br />
<br />
console.log(chalk.blue('Hello world!'));<br />
</pre><br />
<br />
= Webservices using Express =<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-express.html<br />
* [https://stackoverflow.com/questions/32303702/what-is-the-different-between-http-module-and-express-modle What is the different between http module and express modle]:<br />
<br />
:Express is not a "module", it's a framework: it gives you an API, submodules, and methodology and conventions for quickly and easily tying together all the components necessary to put up a modern, functional web server with all the conveniences necessary for that (static asset hosting, templating, handling XSRF, CORS, cookie parsing, POST parsing, you name it, it probably lets you use it).<br />
<br />
:The http API that's baked into Node.js, on the other hand, is just the http module: it can set up HTTP connections and send and receive data, as long as it uses the hypertext transfer protocol (with the relevant HTTP verb) and that's... well that's it really.<br />
<br />
:the Express module is built on top of the http module. It uses the http module for managing the incoming http connections. But, it adds a ton of additional functionality on top of the http module. That is the point of it. For example, if you want to server whole directory of static files (like CSS files or script files) from your node server, that can be done with one line of code in node.js, but would take a lot more code with only the http module<br />
<br />
= Express Generator =<br />
<br />
MVC framework built on Node. Has an express generator that will build the project dirs. From [https://code.visualstudio.com/docs/nodejs/nodejs-tutorial here]:<br />
<br />
Install the Express Generator by running the following from a terminal:<br />
<br />
<pre><br />
npm install -g express-generator<br />
</pre><br />
<br />
The -g switch installs the Express Generator globally on your machine so you can run it from anywhere. You won't want it as part of your project anyway.<br />
<br />
We can now scaffold a new Express application called myExpressApp by running:<br />
<pre><br />
express myExpressApp<br />
</pre><br />
<br />
This creates a new folder called myExpressApp with the contents of your application. To install all of the application's dependencies (again shipped as NPM modules), go to the new folder and execute npm install:<br />
<pre><br />
cd myExpressApp<br />
npm install<br />
</pre><br />
<br />
At this point, we should test that our application runs. The generated Express application has a package.json file which includes a start script to run node ./bin/www. This will start the Node.js application running.<br />
<br />
From a terminal in the Express application folder, run:<br />
<pre><br />
npm start<br />
</pre><br />
<br />
The Node.js web server will start and you can browse to http://localhost:3000 to see the running application.<br />
<br />
= Unit Testing =<br />
<br />
== Mocha ==<br />
<br />
Mocha seems to have the lead among testing frameworks. It runs either in the browser, or in Node. It uses the js engine of either, depending on where it runs.<br />
<br />
* http://www.marcusoft.net/2014/02/mnb-mocha.html - a bit rubbish<br />
* https://webapplog.com/tdd/ - some useful info<br />
* https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - better on setup<br />
<br />
[[File:NoddyExpress.zip]] - my project, minus anything installed locally<br />
<br />
Create '''src''' and '''test''' directories. Then install testing framework and expectation library into the project.<br />
<br />
<pre><br />
npm install mocha --save<br />
npm install chai --save<br />
</pre><br />
<br />
Note that we are using the '''--save''' option to automatically save these dependencies in our package.json file. But probably it should be '''--save-dev'''.<br />
<br />
We will set up the test command inside the package.json file, in order to run our tests simply by executing npm test from the command line.<br />
<br />
The following command is used to invoke the Mocha binary installed locally in the ./node_modules directory:<br />
<pre><br />
./node_modules/.bin/mocha --reporter spec<br />
</pre><br />
<br />
Note that we have also changed the standard reporter that Mocha uses, and set up the spec reporter that is more verbose, and thus more suitable for beginners. You can explore [http://mochajs.org/#reporters other reporters on Mocha's official website].<br />
<br />
Update the test command in package.json to contain the above command. That file should now look like this:<br />
<pre><br />
{<br />
"name": "converter",<br />
"version": "0.0.0",<br />
"description": "",<br />
"main": "index.js",<br />
"scripts": {<br />
"test": "./node_modules/.bin/mocha --reporter spec"<br />
},<br />
"author": "",<br />
"license": "ISC"<br />
}<br />
</pre><br />
<br />
Run it using this command in the project root:<br />
<pre><br />
npm test<br />
</pre><br />
<br />
Chai styles: http://chaijs.com/guide/styles/ Avoid Should!<br />
<br />
Our simple test in the test dir is<br />
<pre><br />
// cd test<br />
// mocha noddyTest.js<br />
// Doesn't require anything else<br />
var assert = require('assert');<br />
<br />
describe('String#split', function(){<br />
it('should return an array', function(){<br />
assert(Array.isArray('a,b,c'.split(',')));<br />
});<br />
})<br />
</pre><br />
<br />
Two files. simple.js in src, just exports a string, no functions.<br />
<pre><br />
var options = 'local';<br />
<br />
exports.options = options;<br />
</pre><br />
<br />
simpleTest.js in test:<br />
<pre><br />
// My first test<br />
'use strict'<br />
<br />
// Import chai, the assert module<br />
const assert = require("chai").assert;<br />
<br />
// Import the code under test<br />
const config = require("../src/simple");<br />
const options = config.options;<br />
<br />
// The test suite<br />
// Sometimes, developers might want to skip a test case/suite (describe.skip() or it.skip()) <br />
// or make them exclusive (describe.only() or describe.only()). <br />
// Exclusivity means that only that particular test runs (the opposite of skip).<br />
describe("Testing import", function () {<br />
<br />
// A test<br />
it("loads options", function (done) {<br />
<br />
console.log('---->' + options);<br />
assert.equal(options, "local");<br />
<br />
done(); // tell mocha that we're done and it can process next test<br />
});<br />
<br />
});<br />
</pre><br />
<br />
=== before and after, beforeEach and afterEach ===<br />
<br />
<pre><br />
describe("test", function() {<br />
<br />
before(() => alert("Testing started – before all tests"));<br />
after(() => alert("Testing finished – after all tests"));<br />
<br />
beforeEach(() => alert("Before a test – enter a test"));<br />
afterEach(() => alert("After a test – exit a test"));<br />
<br />
it('test 1', () => alert(1));<br />
it('test 2', () => alert(2));<br />
<br />
});<br />
</pre><br />
<br />
== Jasmine is used for BDD ==<br />
<br />
But ... is browser based. Try Mocha instead.<br />
<br />
* Jasmine quick start – excellent - http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
My NoddyJasmine.htm, which you just open in Chrome, is:<br />
<br />
<pre><br />
<html><br />
<head><br />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css"><br />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script><br />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script><br />
</head><br />
<body><br />
</body><br />
<script type="text/javascript"><br />
<br />
// Paste in the test code here.<br />
// This example from<br />
// http://www.bradoncode.com/blog/2015/05/12/angularjs-testing-getting-started/<br />
<br />
// The describe function represents a spec (logical grouping of tests). <br />
describe('calculator', function () {<br />
<br />
// The it function indicates a test within the logical grouping. <br />
// The first bit is the displayed test name, the function is the actual test<br />
it('1 + 1 should equal 2, others', function() {<br />
<br />
expect(1 + 1).toBe(2);<br />
<br />
// Other possible tests using Jasmine's expect() method<br />
expect(true).toBe(true);<br />
expect(false).not.toBe(true);<br />
expect(1).toEqual(1);<br />
expect('foo').toEqual('foo');<br />
expect('foo').not.toEqual('bar');<br />
});<br />
<br />
});<br />
<br />
</script><br />
</html><br />
</pre><br />
<br />
== SuperTest for calling APIs ==<br />
<br />
* Extracted from http://www.marcusoft.net/2014/02/mnb-supertest.html<br />
* More good stuff here https://www.codementor.io/knownasilya/testing-express-apis-with-supertest-du107mcv2<br />
<br />
=== GET ===<br />
<br />
The webservice, in '''getApp.js''':<br />
<br />
<pre><br />
var app = require("express")();<br />
<br />
app.get('/user', function(req, res){<br />
res.send(200, { name: 'marcus' });<br />
});<br />
<br />
// In order to reach the app from other modules<br />
// we need to export the express application<br />
module.exports.getApp = app;<br />
</pre><br />
<br />
The test in '''getAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
// Here we get hold of the express application <br />
// by using the exported 'getApp'-property<br />
var app = require("./getApp").getApp;<br />
<br />
describe('GET /users', function(){<br />
it('respond with json', function(done){<br />
// the request-object is the supertest top level api<br />
request(app)<br />
.get('/user')<br />
.set('Accept', 'application/json')<br />
.expect('Content-Type', /json/)<br />
.expect(200, done); // note that we're passing the done as parameter to the expect<br />
});<br />
});<br />
</pre><br />
<br />
=== POST ===<br />
<br />
Post endpoint in '''postApp.js''':<br />
<br />
<pre><br />
var express = require("express");<br />
var app = express();<br />
<br />
app.use(express.bodyParser());<br />
<br />
app.post("/users", function(req, res){<br />
var name = req.body.username;<br />
var email = req.body.email;<br />
<br />
// store it<br />
<br />
res.send(200, name + " is stored");<br />
});<br />
<br />
app.listen(3000);<br />
</pre><br />
<br />
The test - '''postAppTest.js''':<br />
<br />
<pre><br />
var request = require('supertest');<br />
<br />
describe("Posting is easy to test with supertest", function (){<br />
<br />
it("posts a new user to /users", function(done){<br />
var user = { username : 'marcus', email : 'marcus@marcus.com'};<br />
<br />
request("http://localhost:3000")<br />
.post("/users")<br />
.send(user)<br />
.expect(200)<br />
.expect("marcus is stored", done);<br />
});<br />
});<br />
</pre><br />
<br />
== Mocking - use Sinon ==<br />
<br />
Use Sinon instead of Mockito. There’s a before() and after() function. Stub the xhtmlrequest calls.<br />
<br />
== Full example of API tested with Mocha ==<br />
<br />
* [[JavaScript API with Mocha]]<br />
<br />
= Coverage using Istanbul and Mocha =<br />
<br />
* https://stackoverflow.com/questions/16633246/code-coverage-with-mocha<br />
* https://istanbul.js.org/docs/tutorials/mocha/<br />
<br />
<pre><br />
npm install -g istanbul<br />
istanbul cover node_modules/mocha/bin/_mocha -- -R spec<br />
</pre><br />
<br />
(Use ''istanbul cover _mocha -- -R spec'' on other than windows)<br />
<br />
The output is in ''coverage/lcov-report/index.html''<br />
<br />
== nyc - the Istanbul command line interface ==<br />
<br />
I had trouble with this. It just hanged.<br />
<br />
<pre><br />
npm install --save-dev nyc<br />
</pre><br />
<br />
And prefix mocha in your package.json:<br />
<pre><br />
"test": "nyc ./node_modules/.bin/mocha --reporter spec"<br />
</pre><br />
<br />
But I couldn't get it to work. <br />
<br />
* https://github.com/istanbuljs/nyc<br />
<br />
= Database access =<br />
<br />
* [https://blogs.oracle.com/opal/introducing-node-oracledb-a-nodejs-driver-for-oracle-database Oracle driver]<br />
<br />
== Connect to MySQL ==<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mysql.asp<br />
<br />
Install the driver:<br />
<pre><br />
npm install -g mysql<br />
</pre><br />
<br />
Need:<br />
<br />
<pre><br />
// get the module for the driver<br />
var mysql = require('mysql'); <br />
<br />
// Create the connection<br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
console.log("Connected!");<br />
});<br />
</pre><br />
<br />
Run this file using:<br />
<br />
<pre><br />
C:\Users\Your Name>node demo_db_connection.js <br />
</pre><br />
<br />
Query the db with an SQL string:<br />
<br />
<pre><br />
con.connect(function(err) {<br />
<br />
if (err) throw err;<br />
<br />
console.log("Connected!");<br />
<br />
con.query(sql, function (err, result) {<br />
if (err) throw err;<br />
console.log("Result: " + result);<br />
});<br />
<br />
}); <br />
</pre><br />
<br />
All rows: ( https://www.w3schools.com/nodejs/nodejs_mysql_select.asp )<br />
<br />
<pre><br />
var mysql = require('mysql');<br />
<br />
var con = mysql.createConnection({<br />
host: "localhost",<br />
user: "yourusername",<br />
password: "yourpassword",<br />
database: "mydb"<br />
});<br />
<br />
con.connect(function(err) {<br />
if (err) throw err;<br />
con.query("SELECT * FROM customers", function (err, result, fields) {<br />
if (err) throw err;<br />
console.log(result);<br />
});<br />
});<br />
</pre><br />
<br />
== Connect to Postgres ==<br />
<br />
* [https://blog.risingstack.com/node-js-database-tutorial/ Node Hero tutorial] - <br />
<br />
Need the ''pg'' driver.<br />
<br />
<pre><br />
'use strict'<br />
<br />
const pg = require('pg') <br />
const conString = 'postgres://username:password@localhost/node_hero' // make sure to match your own database's credentials<br />
<br />
pg.connect(conString, function (err, client, done) { <br />
if (err) {<br />
return console.error('error fetching client from pool', err)<br />
}<br />
client.query('SELECT $1::varchar AS my_first_query', ['node hero'], function (err, result) {<br />
done()<br />
<br />
if (err) {<br />
return console.error('error happened during query', err)<br />
}<br />
console.log(result.rows[0])<br />
process.exit(0)<br />
})<br />
})<br />
</pre><br />
<br />
<br />
''client.query'' can run any SQL, INSERT, etc.<br />
<br />
== Connect to Mongo ==<br />
<br />
Most use Mongoose library.<br />
<br />
* https://www.w3schools.com/nodejs/nodejs_mongodb.asp<br />
<br />
Get a free MongoDB database at https://www.mongodb.com/<br />
<br />
Get the driver:<br />
<br />
<pre><br />
npm install mongodb <br />
</pre><br />
<br />
= What is Routing? =<br />
<br />
* https://stackoverflow.com/questions/10075507/what-does-javascript-routing-buy-you<br />
<br />
It's a way to go to new pages without reloading the whole webpage again. So much faster.<br />
<br />
:If you want to navigate from one application state, e.g. /admin/users, to another, e.g. /admin/orders, you could use a normal link as you suggest. But then you're going to cause the browser to navigate from one HTML page to another. This is, obviously, the normal way that one navigates around the Web. But in a JavaScript application, this is pretty inefficient!<br />
<br />
:A more efficient way is for the link to fire an event that the application monitors, and for the application to respond by changing the application's state--perhaps by removing or hiding the users view and replacing it with an orders view.<br />
<br />
:This allows the application to maintain the dynamic object model that it's already burned time and used memory to create. It makes the user interface respond more speedily, and, if you're using URL history management via a hashtag or pushState, it allows the user to navigate around your app using the back and forward buttons of their browser, without reloading every asset on the page every time and wiping your application state.<br />
<br />
:URL management also allows deep linking to some page in the application: on load, your app's router examines the route string that it receives, tokenizes it, and loads up the interface you've specified in your routing table.</div>Roger Pearse Warning: Cannot modify header information - headers already sent by (output started at /usr/home/rpearse/public_html/wiki/includes/GlobalFunctions.php:2077) in /usr/home/rpearse/public_html/wiki/includes/WebResponse.php on line 72